java中的虚假唤醒
一 什么是虚假唤醒?
原先条件等待wait()的线程,但是代码块跳过条件wait()被执行。
小二原来做了一碗饭,但是被胡万威胁,于是说自己做了不只是一碗,(这个就是虚假唤醒),原本应该是做一碗,吃一碗,但现在没吃就做了。
二 虚假唤醒的原因
线程的创建是无序的,无法保证线程创建的顺序,当同一个(胡万)线程多次抢到资源时,因为 if 判断,原先的线程在等待(胡万),里面的 条件变量的等待被信号中断。,从而导致出现虚假唤醒,顺序执行以下的步骤,(导致不该多的粉变多了)。
代码案例
package com.ma.sync;
//创建资源 定义属性和方法
class Noodles{
private int num=0; //设定初始值
public synchronized void addNoodles() throws InterruptedException {//增加
if(num!=0){//判断
this.wait();//等待 在哪里睡 就会在哪里醒
}
num++;
System.out.println(Thread.currentThread().getName()+"说六子吃了"+num+"碗");
this.notifyAll();//通知
}
public synchronized void decNoodles() throws InterruptedException {//减少
if(num!=1){//判断
this.wait();//等待
}
num--;
System.out.println(Thread.currentThread().getName()+"自己说吃了1碗,剩余现在"+num+"碗");
this.notifyAll();//通知
}
}
public class ThreadDemo {
public static void main(String[] args) {
Noodles Noodles=new Noodles();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
Noodles.addNoodles();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"小二").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
Noodles.decNoodles();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"六子").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
Noodles.addNoodles();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"胡万").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
Noodles.decNoodles();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"六子").start();
}
}
三如何解决虚假唤醒的问题
我们应该必须防止它通过测试的条件,引起线程被唤醒,并继续执行。换句话说,条件应该在每一次线程调用资源时进行判断,应该把判断放到循环操作里面,wait应该发生在循环中。