synchronized+wait/notify只有一个"等待池",唤醒粒度粗;Lock+Condition可以从同一把锁上分裂出多个独立的等待队列——这篇真实创建两个Condition,验证signalAll()是否真的做到了精确唤醒。
用同一个ReentrantLock创建notEmpty和notFull两个Condition,各自挂起5个线程在await(),然后只signalAll()其中一个。
LockConditionDemo.java Lock lock = new ReentrantLock(); Condition notEmpty = lock.newCondition(); Condition notFull = lock.newCondition(); // 5个线程await(notEmpty), 另5个线程await(notFull) notEmpty.signalAll(); // 只唤醒notEmpty这一组
真实signalAll(notEmpty)后: notEmpty真实被唤醒数=5, notFull真实被唤醒数=0 (应该只有notEmpty组被唤醒) 真实signalAll(notFull)后: notFull真实被唤醒数=5
真实结果证明notEmpty.signalAll()精确地只唤醒了等待在notEmpty这个Condition上的5个线程,另外5个等待在notFull上的线程真实一个都没被惊动,被唤醒数精确为0。这正是Lock+Condition相比synchronized+wait/notify最核心的改进——传统的notify/notifyAll只能对整个对象的monitor操作,一个对象上所有wait()的线程都在同一个等待池里,没有办法区分"生产者在等的"和"消费者在等的";而Condition允许从同一把锁上真实切出多个逻辑独立的等待队列,让精确唤醒(只叫醒真正需要被叫醒的那一组)成为可能,这在经典的生产者-消费者模型(用notEmpty和notFull分别控制"队列不空"和"队列不满"两种等待条件)里非常关键。
LockConditionDemo.java notEmpty.await(); // 在没有lock.lock()的情况下直接调用
真实在未持有锁时调用Condition.await() 抛出: java.lang.IllegalMonitorStateException
每一行都是真实运行这段代码得到的结果(用CountDownLatch控制观测时机)。