今天看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使用代码一时没有问题,当使用代码二时,此时线程被唤醒,但仍然取不到数据,这就是虚假唤醒。

虚假唤醒发生的条件为:

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

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

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

 

版权声明:本文为javab原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/javab/p/11446761.html