2015-05-21 2 views
3

У меня есть трудное время, чтобы действительно понять, как это работает:Почему условия ожидания while-loop безопасны в многопоточном контексте?

while(<some condition>){ 
    wait(); 
} 
OR this example: 
while(<some condition>){ 
    condition.await(); 
} 

Когда нить уже прошла <some condition>, это действительно может случиться, что <some condition> уже false когда wait() или await() казнены.

Таким образом, wait() или await() могут быть вызваны с уже недействительным условием - это означает, что намерение нарушено.

Что не так с моей логикой?

+0

Как это было бы неверно? Если это было уже неверно, Java даже не войдет в цикл while. – user2357112

+0

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

+2

@VladimirNabokov До тех пор, пока поток не вызовет 'wait', он удерживает блокировку. Весь смысл 'wait' - это атомизировать блокировку и ждать. –

ответ

2

С docs для wait():

Текущий поток должен владеть монитором данного объекта. Поток освобождает владельца этого монитора и ждет, пока другой поток не сообщит потокам, ожидающим на мониторе этого объекта, просыпаться либо через вызов метода уведомления, либо метод notifyAll. Затем поток ожидает, пока он не сможет повторно получить право собственности на монитор и возобновит выполнение.

(курсив мой)

Других слов, без synchronized блока, ваш код будет сгенерирован IllegalMonitorStateException. Сsynchronized, с другой стороны, ваше состояние будет проверяться атомарно с помощью вызова wait();.

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


То же рассуждение относится и к использованию Lock с и Condition с. See this code sample. Переменные условий производятся от объектов блокировки, а synchronized/wait/notify аналогичен lock; unlock/await/signal.

+0

правый. плюс вместо синхронизированного ReentrantLock или Condition. –

+1

@VladimirNabokov Я добавил короткий параграф, касающийся 'Lock' и' Condition', если вам интересно. Я сам не использовал API, поэтому я мог бы пропускать вещи, но это должно быть началом. –

+1

Правильно, спасибо, что напомнили мне об обязательной синхронизации. Я знал это, но так легко пропустить ... Ваш блог круто. –

2

Пробуждение от Object#wait() или Condition#await() означает повторное включение соответствующего замка. Предположительно, <some condition> следует изменять только при наличии замка. Итак, если поток, который проснулся, теперь владеет блокировкой, ни один другой поток не сможет изменить условие на false.