Java内置条件队列应用,实现经典的生产者消费者算法( 二 )

测试结果执行结果:t3 的第一个 put 操作会因为缓存已满而阻塞,5 秒后主线程删除两个操作后,重新被唤醒 。主线程的第四个 bu.take() 操作会因为缓存为空而阻塞,直到 t3 在 50 秒后重新插入"last one" 后被唤醒,操作结束 。
Tue Dec 20 10:23:53 CST 2019 buffer is Full thread wait:Thread-2Tue Dec 20 10:23:58 CST 2019 main take:hello1Tue Dec 20 10:23:58 CST 2019 main take:hello2Tue Dec 20 10:23:58 CST 2019 buffer is empty thread wait:mainTue Dec 20 10:23:58 CST 2019 main take:hello3Tue Dec 20 10:23:58 CST 2019 buffer is empty thread wait:mainTue Dec 20 10:24:48 CST 2019 main take:last one...Tue Dec 20 10:24:48 CST 2019 main over...启示录我们的例子中,“非空” 和 “非满” 这两种条件关联着同一个条件队列,当一个线程由于其他线程调用了notifyAll 而被唤醒时,并不意味着它等待的条件已经为真了,这也是内置条件队列的局限所在 。
【Java内置条件队列应用,实现经典的生产者消费者算法】所以代码中的加固措施是,使用循环判断条件是否发生,如果发生,则调用 wait 阻塞自己,等待其他线程唤醒:
while(isFull()){ System.out.println(new Date()+" buffer is Full thread wait:"+Thread.currentThread().getName()); wait();}同样的功能,Java 并发包中的 ArrayBlockingQueue 是使用 ReentrantLock 和 ObjectCondition 实现的可阻塞队列,为什么 JDK 使用显式锁和显式条件队列呢?
使用内置锁的局限性在于一把锁只有一个条件队列,而这里涉及到两种等待条件,所以使用 ReentrantLock 更合适,它可以关联多个条件队列,这样就可以巧妙地处理多条件的阻塞和唤醒了!




推荐阅读