调用 Object.wait() 方法之后

2025/12/18

因为之前看到一个词叫作虚假唤醒,我一遍只是记得书中在强调使用 while 子句进行检查,而不是用if子句检查,但是对这个印象比较深刻。

但是我并不知道是为什么,因为我觉得这两种效果都是一样的,先来看下我之前是如何理解的。

之前的理解

if 版本

synchronized (lock) {  // 2、当线程唤醒后,我之前理解的再次获取锁是从这里开始的
  if (condition == false) {
    lock.wait();  // 1、线程停在这里...
  } 
  doBusinessLogic();
}

where 版本

synchronized (lock) { // 2、当线程唤醒后,我之前理解的再次获取锁是从这里开始的
  while (condition == false) {
    lock.wait();  // 1、线程停在这里...
  }
  doBusinessLogic();
}

如果等待中的线程再次获取锁是从代码块开始的话,那就理解为什么前面我说这两种其实是一样的效果了。

但是其实不是的

修正之后的理解

if 版本

synchronized (lock) {  
  if (condition == false) {
    lock.wait();  // 1、线程停在这里...
  } // 2、当线程唤醒后,继续从停止的下一行开始
  doBusinessLogic();
}

where 版本

synchronized (lock) {
  while (condition == false) {
    lock.wait();  // 1、线程停在这里...
  } // 2、当线程唤醒后,继续从停止的下一行开始
  doBusinessLogic();
}

wait 方法返回后,继续下一行代码的执行。

原因是 wait 方法在返回前就会去尝试获取锁,获取成功后在返回,而不是在 wait 方法外部去获取锁。这个就是差别。

这个知道为什么要用 where 循环了。

如果是 if 版本

synchronized (lock) {  
  if (condition == false) {
    lock.wait();  // 1、线程停在这里...
  } // 2、当线程唤醒后,不会再去检查 condition 了,会直接去执行后面的业务逻辑
  doBusinessLogic();
}

准确的是 where 版本

synchronized (lock) {
  while (condition == false) {
    lock.wait();  // 1、线程停在这里...
  } // 2、当线程唤醒后,会再次检查 condition 条件,不符合则继续等待
  doBusinessLogic();
}

下面图片出自 jdk Object.wait() 文档:

第一个是针对虚假唤醒必须要检查是否真的要唤醒,也就是业务检查

触发 Object.wait() 方法后,就像调用普通方法返回一样,会继续执行剩下的逻辑

再来看下objectMonitor.cpp中针对 wait 方法的实现void ObjectMonitor::wait

也就是说重新获取监视器锁的逻辑就是在 wait 方法中的,被唤醒后并且获取锁成功之后 wait 方法才会返回,不然就会一直等待。