Wait (long timeout) в цикле while?
Я читал, что вы должны помещать вызовы Object.wait()
в Java в цикле while. Причина в том, что этот поток может быть разбужен, и условие, которое вы ожидали оповестить, по-прежнему ложно (ложное пробуждение).
Как насчет Object.wait(long timeout)
. Здесь вы не хотите зацикливаться на этом состоянии, так как вы хотите, чтобы он отключился после указанного количества времени. Но если вы не поместите его в цикл, то как вы можете убедиться, что он не будет разбужен раньше?
Ответы
Ответ 1
Но если вы не ставите его в цикле, то как вы можете убедиться, что он не проснется раньше?
Это недостаток в Java IMO, хотя, возможно, это недостаток в поддержке базового потока в различных вариантах ОС. Я подозреваю, что Java знает, ожидалось ли время ожидания или нет, но нет возможности, чтобы вызывающий мог понять это без повторного тестирования состояния и, в частности, проверки времени. Некрасиво.
Таким образом, вам нужно будет поместить wait(long timeout)
в цикл while
, а также проверить, прошло ли время за период ожидания. Я не знаю другого способа добиться этого.
long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
while (!condition) {
long waitMs = timeoutExpiredMs - System.currentTimeMillis();
if (waitMs <= 0) {
// timeout expired
break;
}
// we assume we are in a synchronized (object) here
object.wait(waitMs);
// we might get improperly awoken here so we loop around to see if we timed out
}
Ответ 2
long deadline = now() + timeout;
synchronized(lock)
while( !condition() && now()<deadline )
lock.wait( deadline - now() );
if(condition())
...
else // timeout
...
Ответ 3
это потому, что у java есть мониторы стиля Mesa вместо мониторов стиля Hoare. Таким образом, вам нужно подождать цикл ожидания.
Пожалуйста, найдите строку "По этой причине обычно необходимо заключить каждую операцию ожидания в цикле, подобном этому" на веб-странице follwing,
http://en.wikipedia.org/wiki/Monitor_(synchronization)#Nonblocking_condition_variables
.если это были мониторы стиля Хоар, тогда вы могли бы поставить свое ожидание в if. Я скоро добавлю детали мониторов Mesa. Это не недостаток Java. Оба типа мониторов имеют преимущества и недостатки.
Ответ 4
Ожидание вызова в цикле не только для обработки случайного побочного пробуждения. В общем случае (не игрушечный пример), когда несколько потоков борются за блокировку, в то время, когда поток просыпается с ожиданием, проверки, сделанные до ожидания, недостаточно для прогнозирования того, в каком состоянии находится объект. который ожидал, отказался от блокировки, поэтому с тех пор все могло случиться, и, кроме того, нет ничего атомарного о том, как работают уведомления, только потому, что вы получили уведомление, это не значит, что другой поток не прокрался в промежуток времени между тем, когда было сделано уведомление и заявленная нить восстановила замок.
В основном вы ждете в цикле, потому что вам нужно проверить текущее состояние с сохраненной блокировкой, чтобы иметь возможность сказать, что происходит. Наличие таймаута не меняет этого. Тайм-аут - это механизм безопасности, поэтому, если уведомление пропущено, нить не будет вечно вешать. Если время ожидания там обычно не требует каких-либо конкретных действий, просто восстановите блокировку, перейдите к телу цикла и проверьте состояние трещины как обычно.
И это не ошибка Java, так работают pthreads.