akash777.sharma akash777.sharma - 3 months ago 13
Java Question

one in one out requirement vs uniform waiters requirement in multi threading java

What are following terms while explaining Bounded buffer example in multi threading:

1.one-in, one-out requirement

2.uniform waiters requirement

I have seen following statement in book java concurrency in practice

BoundedBuffer meets the one-in, one-out requirement, but does not meet the uniform waiters requirement because waiting threads might be waiting for either the “not full” and “not empty” condition.


Can someone explain me the two terms and their difference.

Thanks

Answer

These terms refer to threads that wait() on an arbitrary monitor:

  • uniform waiters: waiting threads are "equal", i.e. they wait for the same condition to become true.
  • one-in, one-out: a notification on the condition allows at most one thread to proceed.

You should only use notify() when both properties are met, otherwise invoke notifyAll() (though it's less efficient).

Goetz explains this on page 303 and gives two concrete examples:

BoundedBuffer meets the one-in, one-out requirement, but does not meet the uniform waiters requirement because waiting threads might be waiting for either the "not full" [producers block on put] and "not empty" [consumers block on take] condition". A "starting gate" latch […] in which a single event releases a set of threads, does not meet the one-in, one-out requirement because opening the starting gate lets multiple threads proceed.

You can also demonstrate this using classes from java.util.concurrent:

BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

new Thread(() -> {
    try {
        TimeUnit.SECONDS.sleep(1L);
        System.out.println("Producer starts.");
        queue.put("foo");
    } catch (InterruptedException e) { /* NOP */ }
}).start();

try {
    System.out.println("Consumer starts.");
    System.out.println(queue.take());
} catch (InterruptedException e) { /* NOP */ }

The consumer has to wait until the producer puts "foo" into the queue. Both wait for different conditions, hence, a BlockingQueue doesn't meet the uniform waiters requirement.

On the other hand, a CountDownLatch meets the uniform waiters requirement, but doesn't meet the one-in, one-out requirement. Once the latch reaches zero, all waiting threads are released:

CountDownLatch latch = new CountDownLatch(1);
Runnable r = () -> {
    try {
        latch.await();
        System.out.println("Thread proceeds.");
    } catch (InterruptedException e) { /* NOP */ }
};

new Thread(r).start();
new Thread(r).start();

try {
    TimeUnit.SECONDS.sleep(1L);
    System.out.println("Count down.");
    latch.countDown();
} catch (InterruptedException e) { /* NOP */ }
Comments