Java并发编程-虚假唤醒现象

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

代码

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.

为什么叫虚假唤醒?

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

你可能感兴趣的:(Java多线程)