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

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

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

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

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

EDIT:

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

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

7 ответов


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

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


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

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

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


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

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


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

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

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


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


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

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


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

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

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