Condition give the effect of having multiple wait-

2019-02-15 23:26发布

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?

3条回答
太酷不给撩
2楼-- · 2019-02-15 23:43

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.

查看更多
干净又极端
3楼-- · 2019-02-15 23:48

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.

查看更多
在下西门庆
4楼-- · 2019-02-16 00:08

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.

查看更多
登录 后发表回答