多线程之虚假唤醒

 今天看JDK文档中的Object.wait()方法,有一段提到:

 对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
     }

大致意思就是,wait()方法需要在循环中使用,以避免实现虚假唤醒。那什么是虚假唤醒,话不多说,贴一段代码来看:

     -----------------------------------------------------代码分隔线-------------------------------------------------------

Thread-1:
while(true) {
    obj = queue.get();  //2
    // 3
}

 

Thread-2:
synchronized(lock) {

    // 代码一
    while(queue.isEmpty()) {
          lock.wait();
    // 4
    }
    obj = queue.get(); // 5

    // 代码二(可能导致虚假唤醒)
    lock.wait();
    // 4
    obj = queue.get(); // 5
}

 

Thread-3:
synchronized(lock) {
    queue.add(obj);
    lock.notify(); // 1
}

     -----------------------------------------------------代码分隔线-------------------------------------------------------

从上面的伪代码看到:

一、有三个线程,对同一数据进行访问

二、线程1未对数据进行安全访问

三、初始状态为:queue.size()==0,代码执行顺序为: 1-->2-->3-->4-->5

四、线程2的目的是当queue为空时等待,不为空时取出数据进行处理

五、线程2的代码一、代码二只能使用其中一种方式。

 

结论:当线程2使用代码一时没有问题,当使用代码二时,此时线程被唤醒,但仍然取不到数据,这就是虚假唤醒。

虚假唤醒发生的条件为:

1、当一个数据存在三个及以上的线程竞争访问时(必要条件)

2、至少有一个线程没有对数据进行加锁访问(充分条件,使得虚假唤醒发生可能)

当满足两个条件才可能发生虚假唤醒。仅仅是可能,如果代码执行顺序为:1-->4-->5-->2-->3,线程二可以取到数据,也就不存在虚假唤醒。

 

解决虚假唤醒(以下任意一种方式即可):

1、所有的线程访问数据时都加锁(线程一就没有加锁)

2、在循环中等待(线程2中的代码一)

 

 

转载于:https://www.cnblogs.com/javab/p/11446761.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值