条件变量是与锁结合使用,用于控制线程同步的,其具有以下基本操作:
- cond.wait(lock, condition),线程在这里判断condition,如果不满足,则解锁,进入休眠状态。
- cond.notifyOne() 随机唤醒一个线程
- cond.notifyAll() 唤醒所有线程
这里的坑就出在这个 notifyAll() 上。虽然这里唤醒了所有线程,但实际上也只有一个线程能获得锁并继续执行,这时就涉及到底层实现了。
当线程因为条件变量陷入等待时,会把他们加入条件变量的等待队列中。此时若有多个线程被唤醒,那么只有竞争到锁的线程才会继续执行。而关键在于其他没有获得锁的线程此时会发生等待转移 --> 从条件变量的等待队列转移到锁的等待队列。这个时候如果一开始那个竞争到锁的线程完成了操作,对条件进行了修改,并最终释放了锁,此时处于锁的等待队列中的线程就会继续竞争锁,并向下执行,但此时的条件已经由 一开始那个竞争到锁的线程进行了修改,条件并不满足,这种情况就容易出现不符合意图的操作。
我们把这种情况称为虚假唤醒。
解决这个问题的办法很简单:
while (condition) {
cond.wait(lock, condition);
}
在最外头添加一个对条件判断的while循环即可,这样即使发生虚假唤醒,也会因为这个while循环检测到条件其实并不满足,从而重新被添加到条件变量的等待队列中。
叨叨几句... NOTHING