Condition Interface in Java

Naveen AnamaneniUpdated · 4 min read

The Condition interface in java.util.concurrent.locks is the Lock version of wait() and notify(). You get a Condition from a lock with lock.newCondition(), and threads call await() to wait and signal() or signalAll() to wake waiters. Its big advantage is that one lock can have several conditions, such as "not full" and "not empty", so you can wake exactly the threads that can make progress. In this lesson, you will learn its methods and rebuild the bounded buffer with two conditions.

Methods

MethodDescription
await()It is used to release the lock and wait until signaled (like wait()).
await(time, unit)It waits at most the given time.
awaitUninterruptibly()It waits and ignores interrupts.
signal()It wakes one waiting thread (like notify()).
signalAll()It wakes all waiting threads (like notifyAll()).

As with wait, the thread must hold the lock when calling these methods, and should await() in a while loop.

Example: A Bounded Buffer with Two Conditions

Let's see an example where producers wait on a notFull condition and consumers wait on a notEmpty condition.

ConditionBuffer.java▶ Try it
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
 
public class ConditionBuffer {
    private final Queue<Integer> items = new ArrayDeque<>();
    private final int capacity = 2;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
 
    void put(int x) throws InterruptedException {
        lock.lock();
        try {
            while (items.size() == capacity) {
                notFull.await();
            }
            items.add(x);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
 
    int take() throws InterruptedException {
        lock.lock();
        try {
            while (items.isEmpty()) {
                notEmpty.await();
            }
            int x = items.remove();
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        ConditionBuffer buffer = new ConditionBuffer();
        int[] sum = new int[1];
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) buffer.put(i);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) sum[0] += buffer.take();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        producer.start();
        consumer.start();
        producer.join();
        consumer.join();
        System.out.println("Advitha's consumer received a total of " + sum[0]);
    }
}
Output
Advitha's consumer received a total of 55

Explanation: The producer waits on notFull while the buffer holds two items; the consumer waits on notEmpty while it is empty. After adding, the producer signals only notEmpty, waking a consumer; after removing, the consumer signals only notFull, waking a producer. All ten numbers (1 to 10, totaling 55) arrive. With plain wait/notify, both kinds of thread share one wait set, so notifyAll must be used and wakes threads that can't proceed.

How BlockingQueue Uses Conditions

Common Mistakes

Calling await() or signal() without holding the lock. It throws IllegalMonitorStateException.

Calling wait() on a Condition object. That's Object.wait; use await().

Using if instead of while around await(). Spurious wakeups apply here too.

Practice

  1. Easy: Add a size() method to ConditionBuffer that takes the lock and returns the number of items.
  2. Harder: Run two producers (each putting 1 to 10) and two consumers (each taking 10 items) on the buffer, and check the total is 110.

Quick check: Condition

4 questions
1How do you get a Condition?
2Which Condition method is like wait()?
3What is the main advantage over wait/notify?
4Must the lock be held when calling signal()?

Key Takeaways

Was this tutorial helpful?

Lesson 419 of 482