Java虚假唤醒

我们知道在synchronized中使用wait和notify会产生虚假唤醒的问题,使用while代替if就可以解决虚假唤醒

具体原因是我们学习wait和notify的时候没有理解清楚,注意:

notify之后被唤醒的那个线程会接着执行而不是重新执行

用一个例子来证明:

public class WaitNotifyTest {
    public static void main(String[] args) {
        Wait wait=new Wait();
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i++) {
                    wait.increament();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i++) {
                    wait.decreament();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B").start();
    }
}

class Wait{
    private Integer num=0;

    public synchronized void increament() throws InterruptedException {
        System.out.println("A被唤醒了");
        while (num!=0){
            System.out.println("重新进入A,然后A执行wait,A被阻塞了,其他线程(包括自己)获得运行机会");
            this.wait();
            System.out.println("A继续执行");
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"->"+num);
        this.notifyAll();
        System.out.println("A唤醒其他的线程");
    }

    public synchronized void decreament() throws InterruptedException {
        System.out.println("B被唤醒了");
        while (num==0){
            System.out.println("重新进入B,然后B执行wait,B被阻塞了,其他线程(包括自己)获得运行机会");
            this.wait();
            System.out.println("B继续执行");
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"->"+num);
        this.notifyAll();
        System.out.println("B唤醒其他的线程");
    }
}

再看执行结果:
在这里插入图片描述
假设notify唤醒的那个线程是重新执行的,那么每次都会打印"A被唤醒了",但是图片中标红的第二段直接打印"A继续执行",说明是继续执行而不是重新执行

理解了notify是继续执行而不是重新执行,那么虚假唤醒就好理解了,如果是用if的话,代码继续执行,那么这个线程获得锁之后就不会再检测条件了(因为if只执行一次,它是不会再次检测num是否等于0的),而是继续执行if代码块下面的语句.当我们使用while的时候,条件语句num!=0会被循环判断,条件为真就会一直循环,条件为假才会继续执行while语句块下面的.

理解的虚假唤醒最重要的一点就是理解notify唤醒的线程会继续执行而不是重新执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值