The Condition interface provides a way to split Object’s wait/notify mechanism into multiple distinct wait sets per lock, giving you more flexible thread coordination than the wait/notify of intrinsic locks.
Advantages of Condition over wait/notify
Multiple “wait”/condition queues: Can have multiple queues (e.g., notFull, notEmpty) for the same lock
More explicit: notEmpty.await() is clearer than wait() on a generic object
Interruptible waits: Better control over thread interruption
class BoundedBuffer<T> { private final Queue<T> queue = new LinkedList<>(); private final int capacity; private final ReentrantLock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); public BoundedBuffer(int capacity) { this.capacity = capacity; } public void put(T item) throws InterruptedException { lock.lock(); try { while (queue.size() == capacity) { notFull.await(); // Wait until buffer not full } queue.add(item); notEmpty.signal(); // Wake up a consumer } finally { lock.unlock(); } } public T take() throws InterruptedException { lock.lock(); try { while (queue.isEmpty()) { notEmpty.await(); // Wait until buffer not empty } T item = queue.remove(); notFull.signal(); // Wake up a producer return item; } finally { lock.unlock(); } }}
Key Methods
await()
Causes the current thread to wait until signalled or interrupted.
Releases the lock automatically before waiting
Reacquires the lock automatically before returning
Thread enters WAITING state, joins the condition’s queue
Variation:
awaitUninterruptibly(): ignores interruptions, only wakes when signalled
lock.lock();try { while (!condition) { // Releases lock, enters wait state & joins condition queue, // joins sync queue when signalled or interrupted (wakes), // reacquires lock before resuming running state and returns notEmpty.await(); } // ... do work} finally { lock.unlock();}
// susceptible to spurious wakeupsif (!condition) { notEmpty.await();}// rechecks condition after wakingwhile (!condition) { notEmpty.await();}
Must Hold the Lock!!!!
All Condition methods (await(), signal(), signalAll(), …) must be called while holding the associated lock, otherwise IllegalMonitorStateException is thrown.
Signalling Doesn’t Release the Lock
signal()/signalAll() doesn’t release the lock.
Thread States
Threads waiting via await(): WAITING state (parked)
Threads waiting via await(timeout): TIMED_WAITING state (parked)
After being signalled: Moved to lock’s sync queue, still WAITING until lock acquired