Condition give the effect of having multiple wait-sets per object?
Asked Answered
G

3

3

I am reading about Condition in java.util.concurrent.locks.Condition .

Condition factors out the Object monitor methods (wait, notify and notifyAll) >into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations.

Can somebody explain me this?

How this is a benefit over normal synchronization blocks or method?

Greasy answered 28/8, 2013 at 14:23 Comment(1)
This should help.Pipette
C
17

One Lock can be associated with many Conditions. Lock is an "object", each condition is a "waiting set". This allows for independent conditions sharing critical section. For example, consider bounded producers-consumers problem. One way to solve it is to have one lock that protects the queue, and two independent waiting sets: one for producers, waiting for slot to place item in the queue, other for consumers waiting for items to take. Using plain old synchronized and wait/notify API, best we can do is along these lines:

  • producer:

    synchronized (lock) {
        while (queue.isFull()) {
            lock.wait();
        }
        queue.put(sth);
        lock.notify();
    }
    
  • consumer:

    synchronized (lock) {
        while (queue.isEmpty() {
            lock.wait();
        }
        product = queue.take();
        lock.notify();
    }
    

This has the disadvantage of waking up both producers and consumers on every change to the queue, even if it cannot possibly allow given thread to proceed (e.g. consumer is awoken when some other consumer takes item from the queue). Using Lock/Condition API we can implement solution that separates waiting consumers and producers, and hence reduce redundant wakeups and checking:

Lock lock = new ReentrantLock();
Condition hasPlace = lock.newCondition();
Condition hasItems = lock.newCondition();
  • producer:

    lock.lock();
    try {
        while (queue.isFull()) {
            hasPlace.await();
        }
        queue.put(sth);
        hasItems.signal();
    } finally {
        lock.unlock();
    }
    
  • consumer:

    lock.lock();
    try {
        while (queue.isEmpty()) {
            hasItems.await();
        }
        product = queue.take();
        hasPlace.signal();
    } finally {
        lock.unlock();
    }
    

This way, consumer waits for producers to produce some item (hasItems condition), and upon removing an item from the queue it notifies producers that there is an empty slot (hasPlace condition). Both conditions are associated with the same critical section (Lock), so we keep the usual exclusion and release-lock-while-waiting guarantees, while gaining the ability to separate waiting queues.

Cambodia answered 28/8, 2013 at 14:33 Comment(3)
There is a ")" missing at your consumers' "while"s :)Crescen
Thanks, can we not simulate the same thing using additional 2 different object(which will be different from lock object used in synchronized block) for using wait and notify essentially replicating the Conditional object ? will it work or wait and notify are independent of the object from which they are called ?Seismography
@Seismography I'm not sure this can be made to work, due to how wait() interacts with the synchronized. When we enter synchronized(lock) section, we take ownership of lock's monitor. Upon calling lock.wait(), we release this ownership so that some other thread can enter synchronized(lock) section and do some work. If we don't call lock.wait() and call someOtherObj.wait() instead, we retain ownership of lock's monitor and no other thread can proceed. That's the trick of Lock and Conditions - there's only one "monitor" (associated with Lock), so this problem doesn't arise.Kornegay
F
1

Previously before the Explicit Locks we used Object wait() and notify() methods for making threads to wait until some event occurred and then triggering them using notify() and the mutex of that Object must be with the thread calling these methods.

So there was only one wait-set per lock object. Wait set is the set where the threads that call wait() on the object are stored (not literraly).

But with the Explicit Lock framework using a single lock you can create multiple wait-sets for different conditions that are related to the same lock. As the example in Javadoc also explain the same fact.

Multiple Conditions == Multiple Wait sets

 final Lock lock = new ReentrantLock(); //Single Lock
 final Condition notFull  = lock.newCondition(); //Multiple conditions
 final Condition notEmpty = lock.newCondition();

So as in the case of Buffer example from JavaDoc consumer threads will wait on the condition for the Buffer to be NOT EMPTY and the producer threads will wait on the condition NOT FULL.

Flanders answered 28/8, 2013 at 14:33 Comment(0)
C
0

For a bounded DataStructure for example, you can have the Conditions "notEmpty" and "notFull" and wait for them. Just one example. Have a look at the example here.

Crescen answered 28/8, 2013 at 14:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.