因为之前看到一个词叫作虚假唤醒,我一遍只是记得书中在强调使用 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 方法才会返回,不然就会一直等待。