Как 2 потока могут получить блокировку после notifyAll? - PullRequest
1 голос
/ 09 июля 2019

Я читал об обмене данными между потоками в Java, используя wait / notify / notifyAll.

Я прошел через этот ответ: https://stackoverflow.com/a/36276832

Есть 2 темы и 1 основная тема. Основной поток сделать notifyAll. Он пробуждает оставшиеся 2 нити, и обе нити печатают

":syncronized block have finished"

Но я читал, что если 2 потока ожидают блокировки, notifyAll будет активировать каждый поток, но блокировка будет получена только 1 потоком.

Итак, мой вопрос: как получается, что потоки t1 и t2 завершают свое выполнение?

Когда я изменяю с lock.notifyAll(); на lock.notify();, программа на Java никогда не заканчивается.

Один поток из t1 / t2 будет в состоянии ожидания.

Может кто-нибудь ответить, пожалуйста. Я могу объяснить мои сомнения в случае, если они не совсем понятны.

Проблема в простых словах: Если 2 потока ожидают одинаковую блокировку, а 3-й поток уведомляет все, только один из них получает блокировку, другой остается в состоянии ожидания, поэтому в приведенном выше случае почему оба потока могут завершить выполнение?

Ответы [ 2 ]

1 голос
/ 10 июля 2019

Когда два потока вызывают wait, последующий notifyAll разбудит их обоих и переведет один в состояние RUNNABLE (победитель синхронизированного захвата на notifyAll), а другой в состояние BLOCKED (ожидание приобрести монитор). Это следует семантике для wait & notifyAll.

Правила для потока BLOCKED - получение монитора после выхода из другого потока RUNNABLE, на котором в данный момент находится монитор. Вот почему вы видите два выхода.

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

1 голос
/ 09 июля 2019

Ответ на ваши вопросы скрыт в документации методов notify () и notifyAll () .

В вашем конкретном случае владельцем объекта блокировки, на котором синхронизируются два потока, является основной поток.Когда мы вызываем метод notify () для объекта блокировки, если вы видите документ, он говорит: « только один поток » проснулся.Отсюда видно, почему программа зависает, второй поток никогда не «просыпается» для пробуждения.Первый поток, который снимет блокировку при переходе в состояние «ожидания», фактически является тем, который пробужден.

Если вы видите документацию «notifyAll ()», в ней говорится «Пробуждает все потоки, ожидающие на мониторе этого объекта. Поток ожидает на мониторе объекта, вызывая один изподождите методы. "акцент на «все» означает, что оба ваших потока, которые получили блокировку и ожидают «уведомления», проснулись.

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

Time: Tue Jul 09 12:42:37 CDT 2019;Thread-1:thread goes into waiting state and releases the lock
Time: Tue Jul 09 12:42:37 CDT 2019;Thread-0:only one thread can be in synchronized block
Time: Tue Jul 09 12:42:42 CDT 2019;Thread-0:thread goes into waiting state and releases the lock
Time: Tue Jul 09 12:42:47 CDT 2019;Notifying all
Time: Tue Jul 09 12:42:47 CDT 2019;Thread-1:thread is awake and have reacquired the lock
Time: Tue Jul 09 12:42:47 CDT 2019;Thread-1:syncronized block have finished
...