https://juejin.cn/post/7085270494672322574
我们可以先来看看,不放在synchronized代码块中使用会有什么问题?
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
obj.wait();
obj.notify();
}
输出结果:
java复制代码
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at xxxx.main(XXX.java:254)
可以看到上面的代码输出结果,直接抛出异常了。下面就讲讲为何会出现这种问题。
wait() 和 notify()是用来实现多个线程之间的一个协调;wait() 表示让线程进入到阻塞状态,notify() 表示让阻塞的线程被唤醒, notifyAll() 则表述唤醒所有被阻塞的线程。 wait() 和 notify() 必然是成对出现的。 如果一个线程被wait()方法阻塞, 那么必然要另一个线程通过notify() 唤醒,从而实现多个线程之间的通信。
在多线程里面要实现多个线程之间的通信,除了管道以外,只能通过共享变量的方式来实现,也就是说第一个线程修改了公共共享变量,别的线程获得修改后的变量的值,从而完成数据的一个通讯;但是多线程的本身是具有并行执行的一个特性,也就是说,在同一个时间,多个线程是可以同时执行的,那么这种情况下,其它现在在访问共享变量之前,必须要知道,第一个线程已经修改了这个共享变量,否则就需要等待,或者是拿到原始数据,基于此基础上运输,产生数据不一致的场景;同时第一个线程在数据修改后,还需要把那个已经处于等待状态下的其它线程唤醒,所以在这种场景下,需要去实现线程之间的通信就必须要有一个静态条件,去控制多线程什么时候条件等待什么时候条件唤醒。而synchronized关键字就可以实现这样一个互斥条件,也就是在通过共享变量来实现多个线程通信的一个场景里面,参与通信的线程必须竞争到这共享变量的一个锁资源,才能够有资格对共享变量进行修改,那么修改完之后释放锁,其他线程就可以再次竞争同一个共享的锁,来获取修改之后的数据,从而完成线程之间的一个通信;所以这就是为什么wait() / notify() 必须需要在synchronized代码块中使用。
有了synchronized同步锁,就可以实现对于多个通信线程之间的一个互斥,从而实现条件等待和条件互斥的唤醒,另外为了避免wait() 和 notify()的错误使用,JDK强制的要求把wait() 和 notify() 写在了同步代码块中,否则就会抛出IllegalMonitorStateException。
/* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout, nanos);
* ... // Perform action appropriate to condition
* }
* </pre>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @param timeout the maximum time to wait in milliseconds.
* @param nanos additional time, in nanoseconds range
* 0-999999.
* @throws IllegalArgumentException if the value of timeout is
* negative or the value of nanos is
* not in the range 0-999999.
* /
作者:东哥Jeffery
链接:<https://juejin.cn/post/7085270494672322574>
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。