Подтвердить что ты не робот

Условие против механизма уведомления о ожидании

В чем преимущество использования интерфейса/реализации Condition над обычным механизмом уведомления о ожидании? Здесь я цитирую комментарии, написанные Дугом Ли:

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

Я вижу, что это более объектно-ориентированный способ реализации механизма ожидания/уведомления. Но есть ли преимущество над первым?

4b9b3361

Ответ 1

Есть много преимуществ , как упомянуто выше о Интерфейсе условий, некоторые из них следующие:

Интерфейс состояния поставляется с Два дополнительными методами, которые:

1) boolean awaitUntil (Date deadline) throws InterruptedException:        Заставляет текущий поток ждать, пока он не будет сигнализирован или не прерван, или истечет указанный крайний срок.

2) awaitUninterruptibly():        Заставляет текущий поток ждать, пока он не будет сигнализирован.

Если текущее состояние прерывания потока установлено, когда оно входит в этот метод, или оно прерывается во время ожидания, оно будет продолжать ждать до тех пор, пока не будет сигнализировано. Когда он окончательно вернется из этого метода, его прерванный статус будет по-прежнему установлен.

Вышеуказанные два метода не присутствуют в стандартном мониторе, который находится в классе объектов, в некоторых ситуациях мы хотим установить крайний срок для потока, который мы ожидаем, тогда мы можем это сделать с помощью интерфейса Condition.

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

Дополнительные сведения Условия Интерфейс Java Документация:

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil%28java.util.Date%29

Ответ 2

Самая большая проблема заключается в том, что wait/notify подвержен ошибкам для новых разработчиков. Основная проблема заключается в том, что вы не знаете, как правильно их обрабатывать, это может привести к ошибке.

  • если вы вызываете notify() перед wait(), он потерян.
  • Иногда бывает непонятно, вызываются ли уведомления() и wait() на одном и том же объекте.
  • В ожидании/уведомлении нет ничего, что требует изменения состояния, но в большинстве случаев это требуется.
  • wait() может возвращаться ложно

Условие завершает эту функциональность в выделенный компонент, однако она ведет себя практически одинаково.

Возникает вопрос о том, что wait/nofity отправили минуты до этого и многие, многие другие Поиск [java] + wait + notify

Ответ 3

Когда вы используете Condition: await()/signal(), вы можете отличить, какой объект или группа объектов/потоков получает конкретный сигнал. Вот краткий пример, когда некоторые потоки, производители, получат сигнал isEmpty, пока потребители получат сигнал isFull:

private volatile boolean usedData = true;//mutex for data
private final Lock lock = new ReentrantLock();
private final Condition isEmpty = lock.newCondition();
private final Condition isFull = lock.newCondition();

public void setData(int data) throws InterruptedException {
    lock.lock();
    try {
        while(!usedData) {//wait for data to be used
            isEmpty.await();
        }
        this.data = data;
        isFull.signal();//broadcast that the data is now full.
        usedData = false;//tell others I created new data.          
    }finally {
        lock.unlock();//interrupt or not, release lock
    }       
}

public void getData() throws InterruptedException{
    lock.lock();
    try {
        while(usedData) {//usedData is lingo for empty
            isFull.await();
        }
        isEmpty.signal();//tell the producers to produce some more.
        usedData = true;//tell others I have used the data.
    }finally {//interrupted or not, always release lock
        lock.unlock();
    }       
}

Ответ 4

Чтобы конкретно указать, почему наличие нескольких waitsets является преимуществом:

С ожиданием/уведомлением, если существуют разные вещи, которые ожидают потоки (общий пример - это блокировка фиксированного размера, причем некоторые потоки помещают вещи в очередь и блокируют, когда очередь заполнена, и другие потоки, взятые из очереди и блокировки, когда очередь пуста), то, если вы используете уведомление, заставляя планировщик выбрать один поток из набора ожидания для уведомления, вы можете иметь угловые случаи, когда выбранный поток не заинтересован в получении уведомления о конкретной ситуации. Например, очередь будет уведомлять о добавлении чего-то в очередь, но если выбранный поток является производителем, а очередь заполнена, то он не может действовать на это уведомление, которое вы предпочитаете использовать для потребителя. С внутренней блокировкой вы должны использовать notifyAll, чтобы удостовериться, что уведомления не теряются.

Но notifyAll берет сбой при каждом вызове, где каждый поток просыпается и защищает блокировку, но только один может добиться прогресса. Остальные потоки все сталкиваются, борясь за блокировку, пока, по одному, они не смогут получить блокировку и, скорее всего, вернутся к ожиданию. Он генерирует много разногласий, не приносящих большой пользы, было бы предпочтительнее иметь возможность использовать уведомление и знать, что уведомляется только один поток, где уведомление относится к этому потоку.

Здесь есть отдельные условия ожидания - это большое улучшение. Очередь может вызывать сигнал при условии и знать, что он пробудит только один поток, где этот поток специально ожидает условие.

API doc for Condition имеет пример кода, который показывает использование нескольких условий для ограниченного буфера, он говорит:

Мы хотели бы продолжать ожидание ставить потоки и принимать потоки в отдельных наборах ожидания, чтобы мы могли использовать оптимизацию только уведомления одного потока в то время, когда элементы или пробелы становятся доступными в буфере.

Ответ 5

@AfterWorkGuinness

Если вы не устанавливаете usedData = true/false перед сигнализацией

После того, как код сигнала дойдет до конца блока блокировки и отпустите его, порядок не имеет значения.