今天总结一下wait-notify-notifyAll 方法,到底该怎么玩。
在使用 wait 方法时,必须把 wait 方法写在 synchronized 保护的 while 代码块中,并始终判断执行条件是否满足,如果满足就往下继续执行,如果不满足就执行 wait 方法,而在执行 wait 方法之前,必须先持有对象的 monitor 锁,也就是通常所说的 synchronized 锁。
如果不要求 wait 方法放在 synchronized 保护的同步代码中使用,而是可以随意调用,会发生什么呢?
首先会造成线程不安全的情况。这个网站上有很多案例 可以自己去搜索。
所以我们在写代码的时候要这样写:
这样就可以确保 notify 方法永远不会在 buffer.isEmpty 和 wait 方法之间被调用,提升了程序的安全性。
//被 synchronized 保护的同步代码
public void notifyTest(String data) {synchronized (this) {buffer.add(data);notify();}
}
//被 synchronized 保护的同步代码
public String waitTest() throws InterruptedException {synchronized (this) {while (buffer.isEmpty()) {wait();}return buffer.remove();}
}
“虚假唤醒”(spurious wakeup)的问题,线程可能在既没有被notify/notifyAll,也没有被中断或者超时的情况下被唤醒。
虽然在实际生产中,虚假唤醒发生的概率很小,但是程序依然需要保证在发生虚假唤醒的时候的正确性,所以就需要采用while循环的结构。
这样即便被虚假唤醒了,也会再次检查while里面的条件,如果不满足条件,就会继续wait,也就消除了虚假唤醒的风险。
相同点:
不同点:
上一篇:安全性归约(一些反例)
下一篇:ERPS环网络端口角色