美文网首页
线程虚假唤醒

线程虚假唤醒

作者: huashu | 来源:发表于2017-06-20 14:25 被阅读0次

一般而言线程调用wait()方法后,需要其他线程调用notify,notifyAll方法后,线程才会从wait方法中返回, 而虚假唤醒(spurious wakeup)是指线程通过其他方式,从wait方法中返回。

下面是一个买票退票的操作例子,买票时,线程A买票,如果发现没有余票,则会调用wait方法,线程进入等待队列中,线程B进行退票操作,余票数量加一,然后调用notify 方法通知等待线程,此时线程A被唤醒执行购票操作。

从程序的顺序性来看 if (remainTicketNum<=0)没有问题,但是为什么会出现虚假唤醒呢?

因为wait方法可以分为三个操作:

(1)释放锁并阻塞

(2)等待条件cond发生

(3)获取通知后,竞争获取锁

假设此时有线程A,C买票,线程A调用wait方法进入等待队列,线程C买票时发现线程B在退票,获取锁失败,线程C阻塞,进入阻塞队列,线程B退票时,余票数量+1(满足条件2 等待条件发生),线程B调用notify方法后,线程C马上竞争获取到锁,购票成功后余票为0,而线程A此时正处于wait方法醒来过程中的第三步(竞争获取锁获取锁),当线程C释放锁,线程A获取锁后,会执行购买的操作,而此时是没有余票的。

解决的办法是条件判断通过while(remainTicketNum<=0)来解决,但是有个问题是如果一直没有退票操作线程Notify,while语句会一直循环执行下去,CPU消耗巨大

public class SpuriousWakeUp {

static Object lock=newObject();

static  int remainTicketNum=0;

public void buyTicket() {

synchronized(lock) {

while(remainTicketNum<=0) {//if (remainTicketNum<=0)虚假唤醒

try{

lock.wait();

}catch(InterruptedException e) {

e.printStackTrace();

}}

remainTicketNum--;

System.out.println(Thread.currentThread().getName() +"购买成功");

}}

public voidreturnTicket() {

synchronized(lock) {

remainTicketNum++;

lock.notify();

System.out.println(Thread.currentThread().getName() +"退票成功");

}}}

PS:wait方法一定是要获取到锁后,才会返回

参考 :

 Java多线程:一道阿里面试题的分析与应对

对条件变量(condition variable)的讨论

相关文章

  • 线程虚假唤醒

    一般而言线程调用wait()方法后,需要其他线程调用notify,notifyAll方法后,线程才会从wait方法...

  • 线程虚假唤醒的Java演示

    什么是线程虚假唤醒 在不同的语言,甚至不同的操作系统上,条件锁都会产生虚假唤醒现象。所有语言的条件锁库都推荐用户把...

  • 线程通信中的虚假唤醒

    今天做了一个关于线程通信的虚假唤醒题。做的时候没想到,对此也不是很熟悉,查过资料才知道原因,在此自己归纳总结一遍。...

  • 虚假唤醒

    原创文章,转载请注明原文章地址,谢谢! 生产者消费者案例 我们先用经典的生产者消费者案例来引出问题。 测试结果 通...

  • 自旋锁在高并发的用处,实现各种锁

    虚假唤醒:由于莫名其妙的原因,线程有可能在没有调用过notify()和notifyAll()的情况下醒来。这就是所...

  • Futex 初学之 虚假唤醒

    用while 代替 if ,防止虚假唤醒。 while( valueneed to wait == true){ ...

  • 虚假唤醒(spurious wakeup)

    On a multi-processor, it may be impossible for an impleme...

  • Java多线程中的虚假唤醒和如何避免

    先来看一个例子 一个卖面的面馆,有一个做面的厨师和一个吃面的食客,需要保证,厨师做一碗面,食客吃一碗面,不能一次性...

  • 2020-08-03如何实现Java线程的 阻塞/唤醒(和暂停/

    如何实现Java线程的 阻塞/唤醒(和暂停/继续 类似 以下为线程 阻塞/唤醒 主要代码 如何使用?

  • 线程核心方法-wait

    ①-1、代码演示使用Object的Notify唤醒wait的线程 ①-2、代码演示使用定时等待唤醒wait的线程 ...

网友评论

      本文标题:线程虚假唤醒

      本文链接:https://www.haomeiwen.com/subject/owjoqxtx.html