1. notify()和notifyAll()的区别
如果某些线程在等待某些条件触发,那当那些条件为真时,你可以用 notify 和 notifyAll来通知那些等待中的线程重新开始运行。
不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll会通知所有等待中的线程。换言之,如果只有一个线程在等待一个信号灯,notify和notifyAll都会通知到这个线程。但如果多个线程在等待这个信
号灯,那么notify只会通知到其中一个,而其它线程并不会收到任何通知,而notifyAll会唤醒所有等待中的线程。
在面试中让应聘者来手写代码,用wait和notify解决生产者消费者问题,我几乎可以肯定他们中的大多数都会无所适从或者犯下一些错误,例如在错误的地方使用 synchronized 关键词,没有对正确的对象使用wait,或者没有遵循规范的代码方法。
第一个问题就是,我们怎么在代码里使用wait()呢?
正确的方法是对在多线程间共享的那个Object来使用wait。在生产者消费者问题中,这个共享的Object就是那个缓冲区队列。
第二个问题是,既然我们应该在synchronized的函数或是对象里调用wait,那哪个对象应该被synchronized呢?答案是,那个你希望上锁的对象就应该被synchronized,即那个在多个线程间被共享的对象。在生产者消费者问题中,应该被synchronized的就是那个缓冲区队列
2. 永远在循环(loop)里调用 wait 和 notify,不是在 If 语句
使用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
}
本文重点:
你可以使用wait和notify函数来实现线程间通信。你可以用它们来实现多线程(>3)之间的通信。
永远在synchronized的函数或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。
永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。
永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。
基于前文提及的理由,更倾向用 notifyAll(),而不是 notify()。