生产者消费者模式中条件判断是使用while而不是if

Posted liuyishi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生产者消费者模式中条件判断是使用while而不是if相关的知识,希望对你有一定的参考价值。

永远在循环(loop)里调用 wait 和 notify,不是在 If 语句现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你应该永远在while循环,而不是if语句中调用wait。因为线程是在某些条件下等待的——在我们的例子里,即“如果缓冲区队列是满的话,那么生产者线程应该等待”,你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,你的线程你也有可能被错误地唤醒。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错——例如在缓冲区为满的时候生产者继续生产数据,或者缓冲区为空的时候消费者开始消耗数据。所以记住,永远在while循环而不是if语句中使用wait!

因为在多核处理器环境中,Signal唤醒操作可能会激活多于一个线程(阻塞在条件变量上的线程),使得多个调用等待的线程返回。所以用while循环对condition多次判断,可以避免这种假唤醒。

基于以上认知,下面这个是使用wait和notify函数的规范代码模板:

// The standard idiom for calling the wait method in Java
synchronized(sharedObject) {
    while(condition) {
        sharedObject.wait();
        // (Releases lock, and reacquires on wakeup)
}
// do action based upon condition e.g. take or put into queue
}

Ps:在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。

注意:

  1. 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。
  2. 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
  3. 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

以上是关于生产者消费者模式中条件判断是使用while而不是if的主要内容,如果未能解决你的问题,请参考以下文章

golang中条件循环控制语句

什么是多线程“伪唤醒“以及为什么要用while循环进行wait判断

java中多线程中测试某个条件的变化用 if 还是用 while?

shell中条件判断文件, 判断数值, 判断字符; 逻辑比较, test的使用

Shell中条件判断语法与判断条件

生产者和消费者模式--java设计模式