如何从另一个任务中取消 ScheduledFuture 任务并优雅地结束?
Posted
技术标签:
【中文标题】如何从另一个任务中取消 ScheduledFuture 任务并优雅地结束?【英文标题】:How to cancel ScheduledFuture task from another task and end gracefully? 【发布时间】:2015-12-20 20:24:45 【问题描述】:我在玩ScheduledExecutorService
。我想要做的是启动一个简单的ticker(每秒一个tick)并稍后安排另一个任务(五秒后)取消第一个任务。然后阻塞主线程直到一切都完成,这应该是在两个任务完成之后(+- 5 秒)。
这是我的代码:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable tickTask = () -> System.out.println("Tick");
ScheduledFuture<?> scheduledTickTask = executor.scheduleAtFixedRate(tickTask, 0, 1, TimeUnit.SECONDS);
Runnable cancelTask = () -> scheduledTickTask.cancel(true);
executor.schedule(cancelTask, 5, TimeUnit.SECONDS);
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
让我吃惊的问题是它会阻塞,就好像还有一些正在运行的任务一样。为什么? cancelTask
应该立即结束,而 scheduledTickTask
刚刚取消,那么问题出在哪里?
【问题讨论】:
【参考方案1】:根据 ExecutorService.awaitTermination
的 Javadoc(强调我的):
阻塞,直到所有任务完成执行关闭请求后,或发生超时,或当前线程被中断,以先发生者为准。
这意味着您需要先致电shutdown
,如下所示:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable tickTask = () -> System.out.println("Tick");
ScheduledFuture<?> scheduledTickTask = executor.scheduleAtFixedRate(tickTask, 0, 1, TimeUnit.SECONDS);
Runnable cancelTask = () ->
scheduledTickTask.cancel(true);
executor.shutdown();
;
executor.schedule(cancelTask, 5, TimeUnit.SECONDS);
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
在您的情况下,超时永远不会发生,因为您实际上将其设置为“无限”并且当前线程没有被中断。
【讨论】:
感谢您的回答,这是我错过的 Javadoc 中的一个简单注释。有没有办法在最后一个任务自动取消后关闭调度程序?或者您必须在某处保留一个计数器并在它为零后关闭? @voho 我不知道这是否可以使用ScheduledExecutorService
。看看this question。以上是关于如何从另一个任务中取消 ScheduledFuture 任务并优雅地结束?的主要内容,如果未能解决你的问题,请参考以下文章
如何运行 db:migrate 从另一个带参数的 rake 任务?