再谈Java的wait(), sleep(), notify()和notifyAll()
一段时间不用java,这些概念就全混淆了,有必要彻底澄清一下,总结在这里,当然以我的本事,不太可能写出水平较高的总结,这里主要是总结stackoverflow上面高人的言论。
先说sleep() 和 wait()
sleep() method causes the current thread to move from running state to block state for a specified time. If the current thread has the lock of any object then it keeps holding it, which means that other threads cannot execute any synchronized method in that class object.
sleep()这个方法是让当年线程从运行态转入阻塞态一段时间,如果当前线程拥有一些对象的锁,那么这个线程将继续拥有,也就意味着其他线程不能执行那些对象的synchronized方法。
注意,sleep()是Thread类的static方法,假如在一个Synchronized块中调用Thread的sleep()方法,虽然线程休眠,但是对象锁还会存在,
wait() method causes the current thread to go into block state either for a specified time or until notify, but in this case the thread releases the lock of the object (which means that other threads can execute any synchronized methods of the calling object.
wait()方法使当前的线程进入阻塞状态直到一段指定的时间结束或者被唤醒,调用wait()会释放对象的锁,也就意味着其他线程可以执行对象的synchronized方法。
注意,wait()方法是Object类的非静态方法,所以每个对象都可以调用。
wait()的使用
a). wait()必须放在synchronized块之中;
这个我前面有一篇blog刚好说这个的:
http://standalone.iteye.com/blog/788259
要执行wait()当前线程必须要先拿到锁。
b). wait()必须放在一个while loop中;
You need not only to loop it but check your condition in the loop. Java does not guarantee that your thread will be woken up only by a notify()/notifyAll() call or the right notify()/notifyAll() call at all. Because of this property the loop-less version might work on your development environment and fail on the production environment unexpectedly.
这个是说有可能睡眠的线程被唤醒不是靠的被notify()/notifyAll()或者被中断,或者时间到了,有一种情况叫spurious wakeup, 你可以点进去看一下高人对此种虚假唤醒的解释。总之,因此要将wait放在一个while循环中,每次醒来自己去检查你的条件是否满足了。
Orcacle的文档也讲了:
public synchronized void put(Object o) { while (buf.size()==MAX_SIZE) { wait(); // called if the buffer is full (try/catch removed for brevity) } buf.add(o); notify(); // called in case there are any getters or putters waiting}public synchronized Object get() { // Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method) while (buf.size()==0) { wait(); // called if the buffer is empty (try/catch removed for brevity) // X: this is where C1 tries to re-acquire the lock (see below) } Object o = buf.remove(0); notify(); // called if there are any getters or putters waiting return o;}