虚假等待
虚假唤醒意味着线程在没有满足 wait() 条件的情况下被唤醒。由于 wait() 可能会由于多种原因(如操作系统调度等)发生虚假唤醒,线程被唤醒后可能发现它原本等待的条件并未改变
示例分析:
public synchronized void produce() throws InterruptedException {
if (queue.size() == 1) {
wait(); // 如果缓冲区满了,生产者等待
}
queue.add(1); // 生产产品
notify(); // 唤醒消费者
}
public synchronized void consume() throws InterruptedException {
if (queue.isEmpty()) {
wait(); // 如果缓冲区空了,消费者等待
}
queue.remove(0); // 消费产品
notify(); // 唤醒生产者
}
这里使用了if来判断是否(满/空);
假设一下步骤发生:
1.生产者线程add(1),然后唤醒其他线程;
2.由于某些原因(比如操作系统调度、虚假唤醒等),消费线程被唤醒,即使缓冲区仍然为空, 它依然开始执行。
3.消费线程执行判断queue.isEmpty(),如果他被虚假唤醒,判断结果为true,然后线程会继续进入消费逻辑,尝试从一个空的缓冲区取数据。
反制生产者亦是。
因为if只能判断一次,如果被虚假唤醒消费线程后,就失效了。 使用 while 循环代替 if 可以解决这个问题,因为 while 会 在每次被唤醒时重新检查条件 ,确保条件符合才继续执行
public synchronized void produce() throws InterruptedException {
wgile (queue.size() == 1) {
wait(); // 如果缓冲区满了,生产者等待
}
queue.add(1); // 生产产品
notify(); // 唤醒消费者
}
public synchronized void consume() throws InterruptedException {
wgile (queue.isEmpty()) {
wait(); // 如果缓冲区空了,消费者等待
}
queue.remove(0); // 消费产品
notify(); // 唤醒生产者
}