Java - Object wait() 方法之虚假唤醒spurious wakeup

Object wait():使一个线程处于等待状态,释放CPU和锁资源

Java Doc 关于 wait 方法的说明如下:

Causes the current thread to wait until either another thread invokes 

The current thread must own this object's monitor. // 否则: IllegalMonitorStateException(正在等待的对象没有锁)

In other words, waits should always occur in loops, like this one: //(防止虚假唤醒 spurious wakeup)

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

线程执行wait方法进入等待后会进入对象的一个等待集合,在以下四种情况下会被唤醒

1.当其他线程调用类notify方法,而恰好当前线程被选择为唤醒线程

2.其他线程调用了notifyAll()方法

3.线程被其他线程中断

4.wait到达了等待的最大时间。如果该时间被设置为0在这种情况不成立,线程会一直等待下去

在Javadoc中特别声明了,在使用wait方法时,最好将wait放在一个loop循环中,因为wait有很小的机率在不通过以上四种方法的情况下被唤醒,该唤醒被称为伪唤醒。

如果不把wait写入loop中,那么有可能导致线程异常执行

 

Spurious Wakeups

http://tutorials.jenkov.com/java-concurrency/thread-signaling.html

For inexplicable reasons it is possible for threads to wake up even if notify() and notifyAll() has not been called. This is known as spurious wakeups. Wakeups without any reason.(唤醒原因尚不明确)

If a spurious wakeup occurs in the MyWaitNofity2 class's doWait() method the waiting thread may continue processing without having received a proper signal to do so! This could cause serious problems in your application.

To guard against spurious wakeups the signal member variable is checked inside a while loop instead of inside an if-statement. Such a while loop is also called a spin lock. The thread awakened spins around until the condition in the spin lock (while loop) becomes false. Here is a modified version of MyWaitNotify2 that shows this:

public class MyWaitNotify3{

  MonitorObject myMonitorObject = new MonitorObject();
  boolean wasSignalled = false;

  public void doWait(){
    synchronized(myMonitorObject){
      while(!wasSignalled){
        try{
          myMonitorObject.wait();
         } catch(InterruptedException e){...}
      }
      //clear signal and continue running.
      wasSignalled = false;
    }
  }

  public void doNotify(){
    synchronized(myMonitorObject){
      wasSignalled = true;
      myMonitorObject.notify();
    }
  }
}

Notice how the wait() call is now nested inside a while loop instead of an if-statement. If the waiting thread wakes up without having received a signal, the wasSignalled member will still be false, and the while loop will execute once more, causing the awakened thread to go back to waiting

当程序调用 wait () 方法之后进入 WAITING 状态,预期 wasSignalled 值设置为 true 后被 notify()

如果被虚假唤醒,此时 wasSignalled值依然为(false),不满足预期, 所以需要对预期条件重复校验,即 while(!wasSignalled)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值