今天我们来看一看,线程之间的通信,也就是我们所说的等待唤醒机制
先来看三个关键方法:
wait();
当线程执行这个方法,它就会进入阻塞状态,并且释放同步监视器
notify();
英文翻译 唤醒,就是说会唤醒wait的线程,注意一点,是唤醒别人,不是唤醒自己,A进入wait 状态 ,需要 B 执行notify 方法去唤醒A,很好理解,你睡着了,不能自己叫醒自己,得闹钟或者别人叫醒你,自然醒那是 sleep()、
如果有多个线程进入阻塞状态,就会唤醒优先级较高的线程
notifyAll();
加了个all,唤醒全部,所有被阻塞的线程全部唤醒
这边举一个通俗的例子:不知道大家小时候有没有玩过 类似 ”全国人民大解放“ 的游戏 ,一个小朋友抓,其他跑,快要被抓住,喊出什么话(这边具体是什么忘了),就不能动了(这边类似你进入wait),得等到别人来拍你,(一般都是会先拍比较厉害的那一个)你才能动 (这边类似notify,别人来唤醒你) ,当仅剩下一个小伙伴在活动,就可以喊出 “全国人民大解放” ,所有人都可以活动(这就类似 notifyAll)
到这,应该对于等待唤醒机制比较了解了
直接上代码,通过代码我们来看看是怎么一回事
比如:
模拟两个线程进行交替打印1-10
首先我们来看看线程没有进行通信,两个线程进行资源抢占的情况:
public class Demo implements Runnable{
int num = 1;
@Override
public 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;
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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 进阶—死锁造成原因及其解决