问题来源

看到了一篇文章阿里面试题,为什么wait()方法要放在同步块中?,如标题所说,里面说了一个关于多线程的问题,但是在阅读过程中提到了几个点

Lost Wake-Up Problem

这是一个在所有多线程环境下都有可能出现的问题。

假如有两个线程,一个消费线程,一个生产者线程。 消费者:

while(count<=0){
    lock.wait();
}
count--;

生产者

count ++ ;
lock.notify();

在多线程环境下,可能会存在消费者线程执行到while,且符合条件,但还未执行wait()时,系统切换开始执行生产者线程,会导致notify()方法执行时无正在等待的线程,之后执行了wait()方法,却又没有其他线程进行通知,导致没有下文了。

解决方式

通过使用同步块,来保证通过对同一个对象资源竞争的方式来确保执行生产者或消费者的执行逻辑是原子性的。

到此其实没有完全说明为什么wait()必须在同步块中 。。。

继续为什么wait必须被同步块包裹着

Java中,执行到synchronized代码块中,其实包含着monitorentermonitorexit指令。 对于wait()方法来说,有如下注释:

This method should only be called by a thread that is the owner of this object's monitor 

IllegalMonitorStateException if the current thread is not the owner of the object's monitor.

指明了lock.wait()调用时必须拿到当前对象的监视器monitor对象

Java强制我们的wait()/notify()调用必须在一个同步块中,不想让我们在不经意间出现这样的Lost Wake-Up Problem。

不仅仅是这两个方法,包含java.util.concurrent.locks.Conditionawait()/signal()也必须要在同步快中。同时Java要求一定要处于对象的同步块中