2014-08-14|1511阅|作者:路易斯陈凯瑞|举报 摘要:java源代码中关于wait和notify的说明有一点是必须在同步块中使用,为什么要这样做呢
关于wait和notify的定义以及使用在java api和《java线程》中都有很详细的说明,这里只是关于wait notify使用时一定要在同步块中这一点进行一些个人思考。
如果纯粹从使用出发解释这个问题,很简单,如果不在同步块中使用,java会抛出IllegalMonitorStateException,这是java API本身的限制。
再深入一点,java为什么要加这个限制?因为这两个方法就是设计给多线程用的,如果你的代码没有多线程或者多线程问题,当然不需要用到这两个方法。
然而这也只是API设计的结果,那么设计的初衷又是什么呢?
首先看一下wait的一段解释:
Note that the <tt>wait</tt> method, as it places the current thread
* into the wait set for this object, unlocks only this object; any
* other objects on which the current thread may be synchronized remain
* locked while the thread waits.
通过这段解释我们可以看到wait的行为是将当前线程放到持有对象的wait set,释放持有对象的锁,目的应该是让其他线程有机会持有该对象的锁。
这里包含两个行为
1)当前线程加入到对象的wait set
这一点其实就是观察者的实现,避免了循环轮询的CPU消耗,改成了监听通知的模式,可以理解,好像和同步不同步没啥关系
2) 释放对象锁
如果wait不在同步块中,就没有办法保证当前线程持有了对象的锁,这个时候如果贸然释放对象锁,很有可能造成错误(释放了别人的锁?当然这已经通过限制避免了),所以个人认为这一点才是wait方法需要在同步块中的原因。
再看notify方法,解释比较长就不贴了,行为很简单
唤醒当前对象的wait set中的任意(arbitrary)一个线程,让该线程有机会去竞争这个对象的锁。
试想,如果notify不在同步块中,那么就没有办法保证当前线程获取了对象的锁,同样对象的锁什么时候会释放也就是个不确定因素;这个时候唤醒一个等待状态的线程加入竞争并没有太大意义,因为你既没有一个可用的资源给他竞争也不确定未来是否会有资源。如果notify在同步块中,那么至少在当前同步块退出的时候就会释放对象锁,使当前对象变成竞争资源。
当然以上观点都是在看《java 线程》时候的一些思考,从方法行为上去揣测设计者的初衷以便更好的理解API,欢迎探讨拍砖