我们不妨来看一下情景:
队列中被添加了一个元素,A,B线程被notifyAll()唤醒,可以取元素.
我们来从代码分析:
若用if:
1 synchronized (monitor) {
2 // 判断条件谓词是否得到满足
3 if(queue.IsEmpty()) {
4 // 等待唤醒
5 monitor.wait(); // 第五行等待状态
6 }
7 // 处理业务逻辑:从队列中取出元素
queue.get();
}
则执行流程为:
线程A取出最后一个元素> A释放锁 -> B得到锁 -> B从第五行向下执行 -> B从队列中取出元素 -> 越界异常
值得注意的是,因为wait住在第五行, 那么A线程执行完后,B线程也被唤醒,并且从第五行向下执行,于是就执行get()方法,发生越界异常.
若用while:
1 synchronized (monitor) {
2 // 判断条件谓词是否得到满足
3 while(queue.IsEmpty()) {
4 // 等待唤醒
5 monitor.wait(); //第五行等待状态
6 }
7 // 处理业务逻辑:从队列中取出元素
}
则执行流程为:
线程A取出最后一个元素> A释放锁 -> B得到锁 -> B从第五行向下执行 -> 又进行while循环 -> 发现队列为空 -> 继续等待
值得注意的是,这里用了while后,虽然也从第五行开始向下执行,但是并不会退出while循环,而是继续进行while判断, 也就不会发生越界异常了.
我们来总结一下: