/*
两个储户,到同一个银行存钱,每个人存了3次,一次100元。
1,描述银行。
2,描述储户任务。分析多线程是否存在安全隐患。1,线程任务中是否有共享的数据。
2,是否多条操作共享数据的代码。同步函数。其实就是在函数上加上了同步关键字进行修饰。
同步表现形式有两种:1,同步代码块,2,同步函数。同步函数使用的锁是什么呢?函数需要被对象调用,哪个对象不确定,但是都用this来表示。
同步函数使用的锁就是this。*/
class Bank
{private int sum;
// private Object obj = new Object();public synchronized void add(int n){
// synchronized(obj)
// {sum = sum + n;try{Thread.sleep(10);}catch(Exception e){}System.out.println("sum="+sum);
// }
}
}
class Customer implements Runnable
{private Bank b &#61; new Bank();public void run(){for(int x&#61;0; x<3; x&#43;&#43;){b.add(100);}}
}class BankDemo
{public static void main(String[] args) {//1,创建任务对象。Customer c &#61; new Customer();Thread t1 &#61; new Thread(c);Thread t2 &#61; new Thread(c);t1.start();t2.start();}
}
/*
验证同步函数使用的锁是this。验证需求&#xff1a;
启动两个线程。
一个线程负责执行同步代码块(使用明锁)。
另一个线程使用同步函数(使用this锁)。
两个执行的任务是一样的都是卖票。如果他们没有使用相同的锁&#xff0c;说明他们没有同步。会出现数据错误。怎么能让一个线程一直在同步代码块中&#xff0c;一个线程在同步函数呢&#xff1f;
可以通过切换的方式。
*/class SaleTicket implements Runnable
{private int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(this){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;"....code....."&#43;tickets--);}}}elsewhile(true)sale();}public synchronized void sale(){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}
}class ThisLockDemo
{public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}
/*
如果同步函数被static修饰呢&#xff1f;static方法随着类加载&#xff0c;这时不一定有该类的对象。但是一定有一个该类的字节码文件对象。
这个对象简单的表示方式就是 类名.class Class*/class SaleTicket implements Runnable
{private static int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(SaleTicket.class){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;"....code....."&#43;tickets--);}}}elsewhile(true)sale();}public static synchronized void sale(){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}
}class StaticLockDemo
{public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}
//饿汉式。相对与多线程并发&#xff0c;安全&#xff01;class Single
{private static final Single SINGLE_INTSTANCE &#61; new Single();private Single(){}public static Single getInstance(){return SINGLE_INTSTANCE;}
}//懒汉式。延迟加载模式。
/*
在多线程并发访问时&#xff0c;会出现线程安全问题。
加了同步就可以解决问题。无论是同步函数&#xff0c;还是同步代码块都行。
但是&#xff0c;效率低了。
怎么解决效率低的问题。
可以通过if对单例对象的双重判断的形式。哦耶&#xff01;*/
class Single
{private static Single s &#61; null;private Single(){}public static Single getInstance(){if(s&#61;&#61;null){synchronized(Single.class){if(s&#61;&#61;null)//-->0 s &#61; new Single();}}return s;}
}class Demo implements Runnable
{public void run(){Single.getInstance();}
}class ThreadSingleTest
{public static void main(String[] args) {System.out.println("Hello World!");}
}
/*
同步函数&#xff0c;同步代码块。同步代码块使用的任意的对象作为锁。
同步函数只能使用this作为锁。如果说&#xff1a;一个类中只需要一个锁&#xff0c;这时可以考虑同步函数&#xff0c;使用this&#xff0c;写法简单。
但是&#xff0c;一个类中如果需要多个锁&#xff0c;还有多个类中使用同一个锁&#xff0c;这时只能使用同步代码块。建议使用同步代码块。*/class
{public static void main(String[] args) {System.out.println("Hello World!");}
}
/*
死锁&#xff1a;场景一&#xff1a;同步嵌套。*/class SaleTicket implements Runnable
{private int tickets &#61; 100;//定义一个boolean标记。boolean flag &#61; true;Object obj &#61; new Object();public void run(){if(flag) while(true){synchronized(obj)//obj lock
{sale();}}elsewhile(true)sale();}public synchronized void sale()//this lock
{synchronized(obj){if(tickets>0){ try{Thread.sleep(10);}catch(InterruptedException e){}//让线程到这里稍微停一下。System.out.println(Thread.currentThread().getName()&#43;".....func...."&#43;tickets--);}}}
}class DeadLockDemo
{public static void main(String[] args) throws InterruptedException{SaleTicket t &#61; new SaleTicket();Thread t1 &#61; new Thread(t);Thread t2 &#61; new Thread(t);t1.start();Thread.sleep(10);t.flag &#61; false;t2.start();}
}
/*
多线程间的通信。多个线程都在处理同一个资源&#xff0c;但是处理的任务却不一样。
生产者&#xff0c;消费者。通过同步&#xff0c;解决了没生产就消费的问题。*/
//描述资源。
class Res
{private String name;private int count &#61; 1;//提供了给商品赋值的方法。public synchronized void set(String name){this.name &#61; name &#43; "--" &#43; count;count&#43;&#43;;System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);}//提供一个获取商品的方法。public synchronized void get(){System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);}
}//生成者。
class Producer implements Runnable
{private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}//消费者
class Consumer implements Runnable
{private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}class ProducerConsumerDemo
{public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);t1.start();t2.start();}
}
//同步嵌套&#xff0c;死锁。class Task implements Runnable
{private boolean flag;Task(boolean flag){this.flag &#61; flag;}public void run(){if(flag){while(true)synchronized(MyLock.LOCKA){System.out.println("if.....locka");synchronized(MyLock.LOCKB){System.out.println("if.....lockb");}}}else{while(true)synchronized(MyLock.LOCKB){System.out.println("else.....lockb");synchronized(MyLock.LOCKA){System.out.println("else.....locka");}}}}
}class MyLock
{public static final Object LOCKA &#61; new Object();public static final Object LOCKB &#61; new Object();
}class DeadLockTest
{public static void main(String[] args) {//创建线程任务。Task t1 &#61; new Task(true);Task t2 &#61; new Task(false);new Thread(t1).start();new Thread(t2).start();}
}
/*
多线程间的通信。多个线程都在处理同一个资源&#xff0c;但是处理的任务却不一样。
生产者&#xff0c;消费者。通过同步&#xff0c;解决了没生产就消费的问题。但是出现了连续的生产没有消费的情况&#xff0c;和需求生产一个&#xff0c;消费一个的情况不符。使用了等待唤醒机制。
wait():该方法可以让线程处于冻结状态&#xff0c;并将线程临时存储到线程池中。
notify():唤醒指定线程池中的任意一个线程。
notifyAll():唤醒指定线程池中的所以线程。这些方法必须使用在同步中&#xff0c;因为它们用来操作同步锁上的线程的状态的。在使用这些方法时&#xff0c;必须标识它们所属于的锁。标识方式就是 锁对象.wait(); 锁对象.notify(); 锁对象.notifyAll();相同锁的notify()&#xff0c;可以获取相同锁的wait();*/
//描述资源。
class Res
{private String name;private int count &#61; 1;//定义标记。private boolean flag;//提供了给商品赋值的方法。public synchronized void set(String name){if(flag)//判断标记为true&#xff0c;执行wait。等待。为false。就生产。try{this.wait();}catch(InterruptedException e){}this.name &#61; name &#43; "--" &#43; count;count&#43;&#43;;System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);//生成完毕&#xff0c;将标记改为true。flag &#61; true;//唤醒消费者。this.notify();}//提供一个获取商品的方法。public synchronized void get(){if(!flag)try{this.wait();}catch(InterruptedException e){}System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);//将标记改为false。flag &#61; false;//唤醒生产者。this.notify();}
}//生成者。
class Producer implements Runnable
{private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}//消费者
class Consumer implements Runnable
{private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}class ProducerConsumerDemo2
{public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);t1.start();t2.start();}
}
/*多生产多消费。问题1&#xff1a;重复生成&#xff0c;重复消费。原因&#xff1a;经过复杂的(等&#xff0c;资格)分析&#xff0c;发现被唤醒的线程没有判断标记就开始工作(生成or消费)了。导致了重复的生成和消费的发生。解决&#xff1a;那就是被唤醒的线程必须判断标记。使用while循环搞定。问题2&#xff1a;死锁了。所有的线程都处于冻结状态。原因&#xff1a;本方线程在唤醒时&#xff0c;又一次唤醒了本方线程。而本方线程循环判断标记&#xff0c;又继续等待。而导致所有的线程都等待了。解决&#xff1b;希望本方如果唤醒了对方线程&#xff0c;就可以解决。可以使用notifyAll()方法。那不是全唤醒了吗&#xff1f;是的。既有本方&#xff0c;又有对方。但是本方醒后&#xff0c;会判断标记继续等待。这样对方就有线程可以执行了。已经实现了多生产多消费。但是有些小问题&#xff0c;效率有点低&#xff0c;因为notifyAll也唤醒了本方。做了不必要的判断。
*///描述资源。
class Res
{private String name;private int count &#61; 1;//定义标记。private boolean flag;//提供了给商品赋值的方法。public synchronized void set(String name)//
{while(flag)//判断标记为true&#xff0c;执行wait。等待。为false。就生产。try{this.wait();}catch(InterruptedException e){}//t0(等) t1(等)this.name &#61; name &#43; "--" &#43; count;//面包1 &#xff0c;面包2 面包3
count&#43;&#43;;//2 3 4
System.out.println(Thread.currentThread().getName()&#43;"...生产者....."&#43;this.name);//t0 面包1、 t0 面包2 t1 &#xff0c;面包3//生成完毕&#xff0c;将标记改为true。flag &#61; true;//唤醒所有等待线程(包括本方线程)。this.notifyAll();}//提供一个获取商品的方法。public synchronized void get()//
{while(!flag)try{this.wait();}catch(InterruptedException e){}//t2(等) t3(等)System.out.println(Thread.currentThread().getName()&#43;".......消费者....."&#43;this.name);//t2 面包1.//将标记改为false。flag &#61; false;//唤醒所有等待线程(包括本方线程)。this.notifyAll();}
}//生成者。
class Producer implements Runnable
{private Res r;Producer(Res r){this.r &#61; r;}public void run(){while(true)r.set("面包");}
}//消费者
class Consumer implements Runnable
{private Res r;Consumer(Res r){this.r &#61; r;}public void run(){ while(true)r.get();}
}class ProducerConsumerDemo3
{public static void main(String[] args) {//1,创建资源。Res r &#61; new Res();//2&#xff0c;创建两个任务。Producer pro &#61; new Producer(r);Consumer con &#61; new Consumer(r);//3,创建线程。Thread t0 &#61; new Thread(pro);Thread t1 &#61; new Thread(pro);Thread t2 &#61; new Thread(con);Thread t3 &#61; new Thread(con);t0.start();t1.start();t2.start();t3.start();}
}
/*1&#xff0c;搞定妖的问题。2&#xff0c;name和sex是私有的。需要在Res类中对外提供访问name和sex的方法。这个可以参照生产者消费者producerconsumerdemo.java3&#xff0c;实现间隔输出&#xff0c;使用等待唤醒机制。producerconsumerdemo2.java*/class Res
{String name;String sex;
}class Input implements Runnable
{private Res r;Input(Res r){this.r &#61; r;}public void run(){int x &#61; 0;while(true){if(x&#61;&#61;0){r.name &#61; "张三";r.sex &#61; "男男男男男男男";}else{r.name &#61; "rose";r.sex &#61; "women";}x &#61; (x&#43;1)%2;}}}class Output implements Runnable
{private Res r;Output(Res r){this.r &#61; r;}public void run(){while(true){System.out.println(r.name&#43;"...."&#43;r.sex);}}}class Test
{public static void main(String[] args) {Res r &#61; new Res();Input in &#61; new Input(r);Output out &#61; new Output(r);new Thread(in).start();new Thread(out).start();}
}