Как отличить, когда ждать (длинный тайм-аут) выход для уведомления или тайм-аут? - PullRequest
28 голосов
/ 03 августа 2010

Имея это объявление ожидания:

public final native void wait(long timeout) throws InterruptedException;

Может завершиться по InterruptedException, или по таймауту, или потому что метод Notify / NotifyAll был вызван в другом потоке, Exception легко перехватить, но ...

Есть ли какой-нибудь способ узнать, был ли причиной выхода является тайм-аут или уведомление?

РЕДАКТИРОВАТЬ:

Это хитрый способ, который может работать, (хотяМне это не нравится)

          long tBefore=System.currentTimeMillis();
          wait(TIMEOUT);
          if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
            { 
               //timeout
            }

Ответы [ 7 ]

15 голосов
/ 03 августа 2010

Существует еще одна причина, по которой уведомление может вернуться: ложное пробуждение.Это маловероятная, но возможная вещь, потому что предотвращение ложных пробуждений очень дорого на некоторых комбинациях аппаратного обеспечения / ОС.

Из-за этого вам всегда нужно вызывать wait () в цикле и повторно проверять условие, которое выждем.Во время этой работы легко одновременно проверить время ожидания.

Для подробностей я рекомендую книгу "Параллелизм Java на практике".И используя конструкции более высокого уровня, которые сделают все это правильным для вас.

12 голосов
/ 03 августа 2010

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

Например, если вы использовали BlockingQueue.poll(long, TimeUnit), вы можете проверить, является ли результат нулевым, чтобы узнать, истекло ли время.

10 голосов
/ 03 августа 2010

Вы не можете различить два, если вы не предоставите некоторый дополнительный код. Например, добавив ThreadLocal Boolean, который установлен на true только для notify()

Но сначала вы должны убедиться, что ваша логика требует этого дифференцирования.

4 голосов
/ 16 декабря 2014

Не используйте System.currentTimeMillis(), используйте System.nanoTime().

Первый измеряет абсолютное время (на основе системных часов) и может иметь любопытные результаты при изменении системного времени. Например: 5-секундное ожидание может длиться час, если часы переместятся назад на час, или 10-минутное ожидание будет сделано через 0 секунд, если часы будут перемещены вперед.

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

2 голосов
/ 03 августа 2010

Нет способа сказать напрямую - то есть вам нужно добавить дополнительный код, чтобы определить это.Часто, когда вы ждете (), вы ожидаете, что произойдет что-то, что каким-то образом изменит состояние объекта - например, установив логическую переменную, возможно.Если это так, то вы можете просто проверить состояние этой переменной, чтобы увидеть, произошло ли событие или просто истекло время ожидания.Или вы можете посмотреть на значение System.currentTimeMillis (), чтобы увидеть, что истекшее время больше или равно периоду тайм-аута - если это так, это будет подсказкой, которую вы, вероятно, истекли (хотя это не абсолютная гарантия).Или, если истекшее время меньше, чем период ожидания, то вы, конечно, не истекло время ожидания.Это помогает?

1 голос
/ 23 июля 2018

Вы должны использовать подход не ждать / уведомлять.

Будет лучше использовать Lock with Condidions https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#await-long-java.util.concurrent.TimeUnit-

Он ожидает с тайм-аутом и вернет false, если время ожидания заметно истекло до возврата из метода, иначе true

1 голос
/ 03 августа 2010

Исключение не выдается при уведомлении и истечении времени ожидания.

Я думаю, что лучше использовать java.lang.concurrent объекты синхронизации пакетов вместо использования Object.wait().

...