Java多线程之虚假唤醒(原创)

Java多线程之虚假唤醒


首先需要说明的是,虚假唤醒不是Java语言特有的问题,而是多线程通信特有的问题,在java中就体现在 sychronized-wait-notify上,最典型的应用场景就是 生产者-消费者模式。

在网上翻看了很多关于虚假唤醒的文档,才发现大多数人说的都是错的。要么语焉不详,要么南辕北辙,不一而足。于是我决定自己写一篇文章来说一说:到底什么是虚假唤醒?


虚假唤醒的定义

无可避免的落入俗套,先放上虚假唤醒的定义。但我要说明的是,这个定义放在这儿你可以只是大致浏览一下,最终请读完整个文章之后再回来看这个定义,应该效果更佳。

A spurious wakeup happens when a thread wakes up from waiting on a condition variable that’s been signaled, only to discover that the condition it was waiting for isn’t satisfied. It’s called spurious because the thread has seemingly been awakened for no reason. But spurious wakeups don’t happen for no reason: they usually happen because, in between the time when the condition variable was signaled and when the waiting thread finally ran, another thread ran and changed the condition. There was a race condition between the threads, with the typical result that sometimes, the thread waking up on the condition variable runs first, winning the race, and sometimes it runs second, losing the race. ----from Wikipedia

当线程从等待状态中被唤醒时,只是发现未满足其正在等待的条件时,就会发生虚假唤醒。 之所以称其为虚假的,是因为该线程似乎无缘无故被唤醒。 虚假唤醒不会无缘无故发生,通常是因为在发起唤醒号和等待线程最终运行之间的临界时间内,线程不再满足竞态条件。

生产者-消费者场景讲起

生产者-消费者是多线程中教程中最常用的教学场景,主要用来模拟进程间通信,映射在java语言上,最常用的语法就是进程间通信三件套sychronized-wait-notify

现在有一个这样的场景,某甜品店进行蛋糕的生产和销售。由于甜品的特殊性,要求甜品店里库存的甜品不能大于100,避免卖不出去浪费。

单生产者-单消费者场景

在这种要求下,我们来使用代码模拟一下。首先假设甜品店只有一个生产进程和一个销售进程。

甜品类:

import java.util.concurrent.TimeUnit;

public class Cookie {
   
    // 甜品库存数目
    // 根据要求,这个值应该满足: 10 =< count <= 100
    private int count;

    public Cookie() {
   
    }

    public int getCount() {
   
        return count;
    }

    public void setCount(int count) {
   
        this.count = count;
    }

    public synchronized void create() {
   
        if (count >= 100) {
   
            try {
   
                System.out.println(Thread.currentThread().getName()+"被挂起,因为此时甜品库存已达到最高位100");
                this.wait();
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
        // 库存尚未达到最高位100
        count++;
        System.out.println(Thread.currentThread().getName()+"生产了一个甜品,当前甜品数目为:"+ count);
        this.notifyAll();
    }

    public synchronized void sale() {
   
        if (count <= 0) {
   
            try {
   
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName()+"被挂起,因为此时已无甜品可卖。");
                this.wait();
            } catch (InterruptedException e) {
   
                e.printStackTrace
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值