Почему невозможно создать двоичный семафор с оператором if внутри Java - PullRequest
0 голосов
/ 20 октября 2018

У меня небольшой вопрос, который меня немного смущает.

Это мой код:

public synchronized void P() {
    while(!_state) {
        this.wait();
    }
    _state = false;
}

Этот метод отвечает за взятие семафора.Почему невозможно создать двоичный семафор с оператором if вместо while loop?

В документации Oracle говорится:

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

Так точно толькоодин поток должен быть внутри метода P () -> поэтому только один поток должен быть заблокирован в методе wait ().Остальные потоки должны быть заблокированы на уровне метода P ().Но когда я заменяю while() на if(), он не работает должным образом

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Почему невозможно создать двоичный семафор с оператором if вместо while цикла?

Для глубокого ответа вам следует работать с Oracle GuardedУчебник по блокам .

Короче, есть несколько причин, по которым _state может быть false при возврате вызова wait():

  1. Несколько потребителей: как правило, безопаснее будить спящих с notifyAll() вместо notify(), и если вы пишете программу, в которой два или более потоков могут вызывать функцию P(), вы, вероятно, захотите только one из них разрешено продолжать, когда какой-то другой поток вызывает функцию V().Так что, если они все «проснутся», вам нужно, чтобы один из них установил _state=false;, и вы захотите, чтобы остальные снова заснули.

  2. Тот же объектполучение notifyAll() звонков по нескольким причинам.Это не очень хорошая практика, но это случается, особенно в проектах, где многие разработчики вносят свой вклад в код.В этом случае вы не хотите, чтобы вызов P() возвращался, если объект был уведомлен по неправильной причине.Вы хотите, чтобы он вернулся и продолжил ожидание.

  3. В документации для o.wait() говорится, что разрешено возвращаться, даже если объект o вообще не был уведомлен.Это известно как «ложное пробуждение».Это случается редко, и только в некоторых операционных системах, но они позволяют это, потому что это обеспечивает более эффективную реализацию wait() и notify().

0 голосов
/ 20 октября 2018

synchronized метод эквивалентен synchronized(this) блоку.

Только 1 поток может войти в синхронизированный блок.Войдя в него, нить aquires lock.Когда вы wait внутри блока синхронизации, вы снимаете блокировку (монитор объекта) и паркуете текущий поток.В этот момент другой поток может войти в этот блок.Выполнение будет продолжено, когда другой поток вызовет notify или notifyAll для того же объекта, который был вызван wait.Уведомленный поток «выйдет из состояния ожидания», когда будет снята блокировка данного блока синхронизации.

Подводя итог: ожидание не работает так, как вы ожидаете, оно не блокирует выполнение, а только переводит ожидающий поток в спящий режим, позволяя другимThreads для синхронизации синхронизации aquire.

Таким образом, вы не можете делать то, что хотите, потому что wait работает не так, как вы ожидаете.То, что вы хотите использовать здесь, это ReentrantLock.https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

...