На самом деле, это не await
, что приводит к зависанию в вашем случае.Это просто поток Timer
, а не демон .JVM не может завершиться, пока все оставшиеся работающие потоки не станут демонами.Как Thread#setDaemon()
javadoc заявляет это:
... Виртуальная машина Java завершает работу, когда все выполняющиеся потоки - все потоки демона.
Так что в вашем случае
- Вы можете просто указать, что поток таймера является демоном
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer(true) //true means the underlying thread is a daemon
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(2, TimeUnit.SECONDS)
println("It's not await that leads to hanging")
Или, если по какой-то причине вы не хотите, чтобы поток вашего таймера был демоном.Например, вы хотите, чтобы таймер обрабатывал все запланированные задачи до завершения JVM.В этом случае вы можете просто отменить таймер в подходящий момент
CountDownLatch called = new CountDownLatch(1)
Timer timer = new Timer() //now the underlying thread is NOT a daemon
timer.schedule(new TimerTask() {
void run() {
called.countDown()
}
}, 0)
assert called.await(2, TimeUnit.SECONDS)
println("It's not await that leads to hanging")
timer.cancel()//now we are done. All scheduled tasks will be cancelled. However, the running one will finish its job
PS Если вы хотите более гибкий способ планирования, вы можете взглянуть на ScheduledThreadPoolExecutor .Как говорит Timer
s javadoc:
... Это фактически более универсальная замена комбинации Timer / TimerTask, так как она позволяет использовать несколько потоков услуг, принимает различные единицы времени и нетребует подклассов TimerTask (просто реализовать Runnable).Настройка ScheduledThreadPoolExecutor с одним потоком делает его эквивалентным Таймеру.