虚假唤醒

今天遇到了并发编程中的虚假唤醒现象, 首先上一段典型的生产者消费者代码:

package juc;

class AirConditioner {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
    	// 出现虚假唤醒
        if (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "\t" + number);
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
    	// 出现虚假唤醒
        if (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "\t" + number);
        this.notifyAll();
    }
}

/**
 * 实现一个线程变量+1, 一个线程变量-1
 * 来10轮
 */
public class ThreadWaitNotifyDemo {

    public static void main(String[] args) {
        AirConditioner airConditioner = new AirConditioner();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(200);
                    airConditioner.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(300);
                    airConditioner.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(400);
                    airConditioner.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(500);
                    airConditioner.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }
}

虚假唤醒的表现
虚假唤醒的表现为: 有时候资源会出现"超卖"现象. 也就是出现负数, 而这是不应该出现的.
关键点就是判断合法性的时候, 使用了if进行判断.

过程
使用if进行判断后, 消费者线程A进入wait()阻塞态, 释放锁, 紧接着有另一个消费者线程B进入, 也进入阻塞态.
紧接着生产者线程C生产, 唤醒两个消费者线程AB, 此时资源数量为1.
如果使用了if, 两个消费者被唤醒后, 线程将继续执行下方的代码块, 导致结果变成-1.

为什么叫虚假唤醒?
站在两个消费者线程的角度上讲, 无论哪一个线程抢到了资源, 另一个线程的唤醒就可以被认为是没有必要的, 也就是被虚假唤醒了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值