0. 前言
1. 正确写法
1.1. wait()正确的写法
synchronized (obj) {
while (<条件不成立>)
obj.wait();
}
1.2. notify()、notifyAll()正确的写法:
synchronized (obj) {
修改wait()的while的条件。
obj.notify();(或者是obj.notifyAll())。
}
2. wait/notify的checklist
2.1. 要有同步(synchronized)
没有同步则不正确。
如果有同步,需要检查同步的对象是否正确,是否是为了wait()才加的同步。
※由于wait时会放锁,所以一定要考虑好同步的对象是否正确。要考虑是否需要大锁套小锁,也就是synchronized里嵌套synchronized。
notify()、notifyAll()也要在同步块中,同步的对象与wait()对应。
2.2. wait()要在while循环中
按照jdk的说明,wait()需要在while循环中。
while循环中检查条件,如果条件不成立则wait()。
(主要是为了防止线程的假醒)
2.3. notify前先修改while循环条件
在notify()或notifyAll()的同步块中先修改针对wait()的while循环中的条件,使while循环中的条件成立(也可能还达不到成立),然后再notify()、notifyAll()。
2.4. notify()或是notifyAll()与wait()是否匹配
找到wait()对应的notify()或是notifyAll()方法,没有则不正确。
另外,查看在notify()或notifyAll()中是否修改了wait()的循环等待条件。参照2.3。
如果使用的是wait(timeout),可以没有notify()或notifyAll(),详细参见2.5。
2.5. 是否会有假醒(spurious wakeups)
通过2的方法保证条件成立时才不继续等待。
需要特别说明的是,
wait(timeOut)也必须遵守2.2的规定;
如果使用的是wait(timeOut)方法,又没有notify()或是notifyAll(),
则需要看是否只是为了计时,如果是,则应该使用sleep(timeOut)方法。
由于遵守2.2,即使假醒,wait(timeOut)的条件不成立的话,还会继续wait(timeOut)。
2.6. notify()或notifyAll()是否会在wait()之前被调用。
看notify()或是notifyAll()是否会在wait()之前调用
如果不会,则不需要处理;
如果会,需要检查notify()或是notifyAll()在wait()之前被调用是否是有问题。
如果没有问题,则要保证wait()之前的while循环条件的逻辑正确,保证不会一直wait()。
2.7. 如果不是notifyAll()需要检查notify()是否有问题。
由于调用notify(),不知道究竟哪个等待线程被唤醒,
所以一定保证wait的条件正确。
只有满足条件的线程才会继续执行,其他线程还是处于wait()状态。
2.8. 如果有多个线程同时在wait()一个对象时,notifyAll()时是否会有问题。
是否是预期的那个wait()的操作完成了。
例如:发送request后等待response,当有response回来的时候,检查是否是对应request的response回来时才notify()。
这种情况关键要看wait()的条件是否正确。
所以在设置wait()的条件的时候,要检查wait()的while()条件设置是否合理,
同时也要检查notify()或notifyAll()前修改wait()的while()条件是否正确。