Search code examples
javamultithreadingsynchronizationproducer-consumerjava.util.concurrent

Producer/Consumer in Java. Why do we need two conditions?


I've read about the problem on https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html.

This is what the documentation says about the two conditions:

We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer. This can be achieved using two Condition instances.

I could notify a single thread using one condition since signal() wakes up one thread:

class BoundedBuffer2 {
    final Lock lock = new ReentrantLock();
    final Condition condition  = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                condition.await();
            items[putptr] = x;
            if (++putptr == items.length) putptr = 0;
            ++count;
            condition.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                condition.await();
            Object x = items[takeptr];
            if (++takeptr == items.length) takeptr = 0;
            --count;
            condition.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}

Why do we need two conditions?


Solution

  • Say your buffer was empty and two threads were waiting on take, blocked on

    condition.await();
    

    Then a thread calls put. This will signal the Condition and wake up one of the take threads. That take thread will subsequently also signal the Condition, waking up the other take thread which will loop back in blocking state since there is nothing for it to take.

    That last signal was unnecessary. That second take thread should never have been woken up since nothing was available.

    The two condition algorithm allows you to notify only those threads that are relevant.