Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java conditions: protected predicates and timed waiting

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A Condition lets a thread release its associated lock while waiting for a protected predicate to become true, then reacquire that lock before continuing.

Java 8+. This is a complete program using JDK classes.

Wait for state, not a message

A receiving desk waits for an inventory count greater than zero. A signal says that a state change may have occurred; it does not hand the waiting thread a reserved item. Another consumer can take that item before the awakened thread reacquires the lock.

Check the predicate in a while loop. The loop handles both competing consumers and spurious wakeups. The code decrements its count only while holding the same lock used by the producer. Updating the count outside that lock would separate the signal from the state that the waiting code actually observes.

The method accepts a remaining nanosecond budget. awaitNanos reports what remains so repeated wakeups do not restart the full wait. Lock acquisition uses lockInterruptibly, making interruption an explicit way to leave both the admission and waiting phases.

Keep cleanup outside the success assumption

The finally block releases the lock after success, timeout or a waiting exception. A timed-out consumer returns false without inventing an item. Production shutdown needs another protected predicate, such as closed, and a signalAll so all waiting callers can recheck that state.

Working program

Java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReceivingDeskCondition {
    final ReentrantLock lock = new ReentrantLock();
    final Condition available = lock.newCondition();
    int parcels;
    void receive() {
        lock.lock();
        try { parcels++; available.signal(); }
        finally { lock.unlock(); }
    }
    boolean take(long budgetNanos) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (parcels == 0) {
                if (budgetNanos <= 0) return false;
                budgetNanos = available.awaitNanos(budgetNanos);
            }
            parcels--; return true;
        } finally { lock.unlock(); }
    }
    public static void main(String[] args) throws Exception {
        ReceivingDeskCondition desk = new ReceivingDeskCondition();
        System.out.println(desk.take(0));
        desk.receive();
        System.out.println(desk.take(0));
        System.out.println(desk.take(0));
    }
}

Output

Output
false
true
false

Costs and boundaries

The protected state transition is O(1), but a waiting call can spend its budget blocked. That budget applies to condition waiting, not the earlier lock acquisition or a complete method deadline. Scheduling and lock contention are not bounded by the few arithmetic instructions. This fixture verifies timeout and state transitions without relying on thread timing; the download checks also exercise a signalled waiter.

Common Mistakes

  • An if check cannot protect against repeated wakeups.
  • Use the same lock for the predicate, update and waiting operation.
  • Signal does not transfer ownership of an item.

Read next

Lock ownership, Library queue alternatives.

java
conditions
Storage details