在平常开发,咱们都知道wait/notify有着很是固定的一套模板,就是下面的样子,synchronized同步块包裹着Object.wait()
方法,若是不经过同步块包住的话JVM会抛出IllegalMonitorStateException
异常。java
synchronized(lock) { while(!condition){ lock.wait(); } }
那么为何要限制这么写呢?多线程
假设咱们本身实现了一个BlockingQueue的代码。
若是Object.wait()/notify不须要同步,那么咱们的代码会形以下面这样。spa
class BlockingQueue { Queue<String> buffer = new LinkedList<String>(); public void give(String data) { buffer.add(data); notify(); // 往队列里添加的时候notify,由于可能有人在等着take } public String take() throws InterruptedException { while (buffer.isEmpty()) // 用while,防止spurious wakeups(虚假唤醒) wait(); // 当buffer是空的时候就等着别人give return buffer.remove(); } }
若是上面的代码能够执行的话,多线程状况下会出现一种状况:线程
由于你只要用notify,那就是为了在多线程环境下同步,notify/wait机制自己就是为了多线程的同步而存在的,那就只能配套synchronized,因此为了防止上面状况的发生,就直接强制抛异常来限制开发的代码模式了。code
试想一种场景,若是没有wait/notify的挂起唤醒机制,该如何实现BlockingQueueblog
class BlockingQueue { Queue<String> buffer = new LinkedList<String>(); public void give(String data) { buffer.add(data); } public String take() throws InterruptedException { while(buffer.isEmpty) { sleep(10); } return buffer.remove(); } }
若是没有wait/notify,那么在take的时候只能经过while循环不停轮询判断buffer是否为空来实时获取buffer的最新状态,那么势必会形成两种状况:队列
综上,针对于BlockingQueue这样的场景,同步块 + wait/notify 或者 lock + signal/await 就是标配开发