Condition Interface Signalling Methods

Example Flow

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.

Creating Conditions

Conditions are created from a Lock instance:

ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

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();
}

analogous to Object.wait()

await(long time, TimeUnit unit)

Same as await() but with a timeout.

  • Returns true if signalled before timeout
  • Returns false if timeout elapsed
  • Thread enters TIMED_WAITING state
  • Variations:
    • awaitNanos(nanos): nano second precision
    • awaitUntill(date): until after a specific date
if (!notEmpty.await(5, TimeUnit.SECONDS)) {
    // Timeout - condition wasn't signaled in time
}

analogous to Object.wait(long timeout)

signal()

Wakes up one waiting thread from this condition’s queue.

  • If the lock is fair, wakes the longest-waiting thread
  • If the lock is unfair, chooses arbitrarily
  • The awakened thread must still reacquire the lock before proceeding
lock.lock();
try {
    // ... modify state
    notEmpty.signal(); // Wake up one waiting consumer
} finally {
    lock.unlock();
}

analogous to Object.notify()

signalAll()

Wakes up all waiting threads from this condition’s queue.

lock.lock();
try {
    // ... major state change
    notEmpty.signalAll(); // Wake up all waiting consumers
} finally {
    lock.unlock();
}

analogous to Object.notifyAll()

Important Notes

Always Use While Loops, Not If

// susceptible to spurious wakeups
if (!condition) {
    notEmpty.await();
}
 
// rechecks condition after waking
while (!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