java中的虚假唤醒(让子弹飞里面的六子到底吃了几碗粉)

本文探讨了Java中线程同步时可能出现的虚假唤醒现象,即线程在未满足条件时被错误唤醒。通过一个Noodles类的例子,展示了在多线程环境下,由于线程的无序创建和wait/notify机制可能导致的虚假唤醒。为了解决这个问题,文章建议将条件判断放入循环中,确保线程在执行前检查条件是否满足,避免虚假唤醒导致的错误执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 什么是虚假唤醒?

原先条件等待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应该发生在循环中。
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值