先思考如果wait、notify不在synchronized保护的同步代码中的样子:
//经典的生产者与消费者
public class BlockingQueue{
Queue<String> buffer=new LinkedList<String>();
//负责往buffer中添加数据,添加完后执行notify唤醒之前等待的线程。
public void give(String data){
buffer.add(data);
notify();
}
// 负责检查整个buffer是否为空,如果为空,就等待;否则,就取出一个数据。
public String take() throws InterruptedException{
while(buffer.isEmpty()){
wait();
}
return buffer.remove;
}
}
以上代码没有受synchronized保护,可能会发生以下情况:
- 首先,消息者线程调用take()方法并判断buffer.isEmpty方法是否返回true,为true代表buffer是空的,则线程进入等待状态。但是在线程调用wait方法之前,就被调度器暂停了,而此时还未来得及执行wait方法
- 其次,生产者执行整个give方法,并执行了notify方法,但是没有任何效果,因为take()方法的wait还没有执行。
- 再次,执行被调度器暂停的消费者线程,继续执行wait方法,等待中。因为 buffer.isEmpyt、wait,即判断与执行不是一个原子操作,它在中间被打破了,是线程不安全的。
- 最后,如果此时没有更多的生产者进行生产,那么消费者便可能陷入无穷的等待中,因为其刚才错过了notify方法。
因此,应该在两个方法前加synchronized关键字,获得对象的锁monitor。 否则,抛出IllegalMonitorStateException异常,wait、notify间也存在潜在的竞态条件。
参考:
https://zhuanlan.zhihu.com/p/138770887
https://blog.youkuaiyun.com/youanyyou/article/details/107310028