今天我们来看一看,线程之间的通信,也就是我们所说的等待唤醒机制
先来看三个关键方法:
wait();
当线程执行这个方法,它就会进入阻塞状态,并且释放同步监视器
notify();
英文翻译 唤醒,就是说会唤醒wait的线程,注意一点,是唤醒别人,不是唤醒自己,A进入wait 状态 ,需要 B 执行notify 方法去唤醒A,很好理解,你睡着了,不能自己叫醒自己,得闹钟或者别人叫醒你,自然醒那是 sleep()、
如果有多个线程进入阻塞状态,就会唤醒优先级较高的线程
notifyAll();
加了个all,唤醒全部,所有被阻塞的线程全部唤醒
这边举一个通俗的例子:不知道大家小时候有没有玩过 类似 ”全国人民大解放“ 的游戏 ,一个小朋友抓,其他跑,快要被抓住,喊出什么话(这边具体是什么忘了),就不能动了(这边类似你进入wait),得等到别人来拍你,(一般都是会先拍比较厉害的那一个)你才能动 (这边类似notify,别人来唤醒你) ,当仅剩下一个小伙伴在活动,就可以喊出 “全国人民大解放” ,所有人都可以活动(这就类似 notifyAll)
到这,应该对于等待唤醒机制比较了解了
直接上代码,通过代码我们来看看是怎么一回事
比如:
模拟两个线程进行交替打印1-10
首先我们来看看线程没有进行通信,两个线程进行资源抢占的情况:
public class Demo implements Runnable{int num = 1;@Overridepublic void run() {while (true) {synchronized (this) {if (num<=10) {System.out.println(Thread.currentThread().getName()+":"+num);num++;} else {break;}}}}public static void main(String[] args) {Demo demo =new Demo();Thread thread1 =new Thread(demo,"线程1");Thread thread2 =new Thread(demo,"线程2");thread1.start();thread2.start();}
}
可以看到所有资源都被线程1抢占,不符合我们的需求
接下来看看两个线程间进行通信后的结果
public class Demo implements Runnable{int num = 1;@Overridepublic void run() {while (true) {synchronized (this) {notify();if (num<=10) {System.out.println(Thread.currentThread().getName()+":"+num);num++;try {//使线程进入阻塞wait();} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}}}public static void main(String[] args) {Demo demo =new Demo();Thread thread1 =new Thread(demo,"线程1");Thread thread2 =new Thread(demo,"线程2");thread1.start();thread2.start();}
}
线程间通信就引出了一个生产者,消费者的问题
就比如去饭店吃饭,得有饭才能去吃
生产者:Productor
public class Productor implements Runnable{List<String> list = new ArrayList<>();public Productor(List<String> list) {this.list = list;}@Overridepublic void run() {int num = 0;while (true) {synchronized (list) {if (list.size() == 0) {num++;//没有饭生产list.add("第" + num + "份米饭");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "生产了" + list.get(0));list.notify();} else {// 有饭等待消费者消费try {list.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}
}
消费者:
public class Consumer implements Runnable{List<String> list;public Consumer(List<String> list) {this.list = list;}@Overridepublic void run() {while (true) {synchronized (list) {if (list.size() > 0) {//有饭消费,并通知生产者try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "消费了" + list.get(0));list.remove(0);list.notify();} else {//无饭等待try {list.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}
}
进行创建线程
public static void main(String[] args) {List<String> list = new ArrayList<>();Productor productor =new Productor(list);Consumer consumer =new Consumer(list);new Thread(productor,"小红").start();new Thread(consumer,"小明").start();}
输出结果:
以上就是等待唤醒机制的全部内容了
java进阶—多线程
java 进阶—线程的常用方法
java进阶—线程安全问题
Java 进阶—死锁造成原因及其解决