Условие дает эффект наличия нескольких наборов ожидания для каждого объекта?

Я читаю о состоянии в java.util.concurrent.locks.Condition .

Условие выделяет методы монитора объекта (wait, notify и notifyAll)> в отдельные объекты, чтобы создать эффект наличия нескольких наборов ожидания для каждого объекта, комбинируя их с использованием произвольных реализаций блокировки.

Может ли кто-нибудь объяснить мне это?

В чем преимущество перед обычными блоками или методами синхронизации?


person Thinker    schedule 28.08.2013    source источник
comment
Это должно помочь.   -  person Boris the Spider    schedule 28.08.2013


Ответы (3)


Одна Блокировка может быть связана со многими Условиями. Блокировка — это «объект», каждое условие — это «ожидающий набор». Это позволяет использовать независимые условия для совместного использования критической секции. Например, рассмотрим ограниченную задачу производителей-потребителей. Один из способов решить эту проблему — иметь одну блокировку, защищающую очередь, и два независимых набора ожидания: один для производителей, ожидающих, когда слот поместит элемент в очередь, другой — для потребителей, ожидающих получения предметов. Используя старые добрые synchronized и wait/notify API, лучше всего мы можем сделать следующее:

  • режиссер:

    synchronized (lock) {
        while (queue.isFull()) {
            lock.wait();
        }
        queue.put(sth);
        lock.notify();
    }
    
  • потребитель:

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

Недостатком этого является пробуждение как производителей, так и потребителей при каждом изменении в очереди, даже если это не может позволить данному потоку продолжаться (например, потребитель пробуждается, когда какой-то другой потребитель берет элемент из очереди). . Используя Lock/Condition API, мы можем реализовать решение, которое разделяет ожидающих потребителей и производителей и, следовательно, уменьшает избыточные пробуждения и проверки:

Lock lock = new ReentrantLock();
Condition hasPlace = lock.newCondition();
Condition hasItems = lock.newCondition();
  • режиссер:

    lock.lock();
    try {
        while (queue.isFull()) {
            hasPlace.await();
        }
        queue.put(sth);
        hasItems.signal();
    } finally {
        lock.unlock();
    }
    
  • потребитель:

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

Таким образом, потребитель ждет, пока производители произведут какой-либо предмет (условие hasItems), и, удаляя предмет из очереди, уведомляет производителей о наличии свободного места (условие hasPlace). Оба условия связаны с одной и той же критической секцией (Lock), поэтому мы сохраняем обычные гарантии исключения и снятия блокировки во время ожидания, получая при этом возможность разделять очереди ожидания.

person Marcin Łoś    schedule 28.08.2013
comment
В то время как ваши потребители отсутствуют :) - person Fildor; 28.08.2013

Например, для ограниченной структуры данных вы можете иметь условия «notEmpty» и «notFull» и ждать их. Всего один пример. Взгляните на пример здесь.

person Fildor    schedule 28.08.2013

Ранее, до явных блокировок, мы использовали методы объекта wait() и notify(), чтобы заставить потоки ждать, пока не произойдет какое-то событие, а затем запускать их с помощью notify(), а мьютекс этого объекта должен быть с потоком, вызывающим эти методы.

Таким образом, для каждого объекта блокировки был только один набор ожидания. Набор ожидания — это набор, в котором хранятся потоки, вызывающие wait() для объекта (не буквально).

Но с помощью платформы Explicit Lock, использующей одну блокировку, вы можете создать несколько наборов ожидания для разных условий, связанных с одной и той же блокировкой. В качестве примера в Javadoc также поясняется тот же факт.

Multiple Conditions == Multiple Wait sets

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

Как и в случае с примером Buffer из Потоки-потребители JavaDoc будут ожидать, пока буфер НЕ ПУСТОЙ, а потоки-производители будут ждать, пока не будет заполнено условие.

person Narendra Pathai    schedule 28.08.2013