如何高效地重置线程池

4
我正在使用线程池来启用多个不重要的任务排队并(可能)执行,但我需要能够轻松取消所有已排队和正在执行的任务,并从头开始启动新的队列。
例如:
// startup
pool = Executors.newFixedThreadPool(5);

// reset
pool.shutdownNow();
pool = Executors.newFixedThreadPool(5);

我现在使用的实现似乎可以工作,但我不确定完全关闭并创建一个新的线程池是否特别高效。

重置操作经常发生,在某些用法中,它与调度任务一样频繁!由于无法确定是否有任何任务等待执行(或者有吗?),因此我觉得我经常关闭池。

是否有更合适的池实现或更好的方法来实现此功能?

编辑:解决方案

我现在使用以下内容:

// startup
pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);

// reset
for (Future<?> task : pool.getQueue().toArray(new Future[0]))
    task.cancel(true);

我忽略了对“清除”调用的操作,因为这很慢,队列将被池稍后整理。我知道当前正在执行的任务可能不会被终止,但这对我来说是可以接受的。

谢谢。


如果你已经回答了你的问题,请将答案放在答案部分,而不是问题部分。 - Nicol Bolas
@NicolBolas感谢您的投票和训斥。我使用了其中一位海报的答案,这非常有帮助,但是想澄清我的用法,以便将来有所帮助。我不想通过自我回答复制别人的东西来声称所有荣耀。你们中的一些人太珍贵了,这真的会减少使用网络上最有用的资源的乐趣。为什么不把注意力转向那些真正需要帮助的帖子,而不是对已经解决并且好问题进行评论呢?祝你有美好的一天。 - pstanton
“我不想通过自问自答并复制别人的内容来独占所有荣耀。” 然后发布您的答案并点赞/接受“他们”的答案。这不是关于“独占荣耀”,而是关于适当的组织。问题放在顶部,“答案”放在“答案”部分。这就是使其成为“有用资源”的原因。回答自己的问题是可以的。“为什么不把注意力转向那些真正需要帮助的帖子,而不是参与已经解决和其他好问题的讨论。” 当您在问题中提供了一个“答案”时,它就不再是一个“好问题”了。 因此被投下反对票。 - Nicol Bolas
因人而异。 - pstanton
2个回答

0

您可以监视从提交任务中获取的所有Future,并cancel()所有这些Future,这样就可以重复使用线程池而无需重新创建。但是,我怀疑您不会获得太多额外的效率。

只要您不经常这样做,我认为您的机制应该可以正常工作。需要注意的一点是,尽管您调用了pool.shutdownNow(),但这只会中断正在运行的任务,这些任务不一定会停止。这取决于它们正在执行什么操作以及它们是否在监听线程中断标志或抛出InterruptedException异常的方法。因此,即使shutdownNow()返回,某些任务仍可能在执行。


是的,我明白关闭和取消操作并不一定会停止正在运行的任务/线程。但是,取消任务在执行之前肯定比终止并重新创建所有内容(包括线程、队列等)更有效率,对吧? - pstanton
更高效,但我只能说略有提升。这取决于你执行的频率。这意味着你需要添加代码来管理正在运行的任务列表,这也是额外的负担。我怀疑当你测试新方法时,你不会看到显著的差异。你选择的答案在两次完全错误,直到我纠正它并且一开始就提出了那种机制。但是,好吧@pstanton。 - Gray
+1并感谢您的回答,ThreadPoolExecutor.getQueue意味着我不必管理列表。感谢您的帮助。我不确定为什么有人会对您的答案进行负投票,而且没有评论... - pstanton

-2

您可以取消所有待处理(可能正在运行)的任务:

for (Future f: pool.getQueue().toArray(new Future[0]))
{
    f.cancel(true); // or false
}
pool.purge();

FutureExecutorService内部的包装器。您不需要自己实现Future。使用cancel(...)方法并不能中断相关联的线程。 - Gray
不,@Valeri,它也不是那样工作的。那些仍然被视为只是“Runnable”。FutureTask只能由并发类创建。 - Gray
@Gray 我不明白为什么你不能创建 FutureTask。http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html - Valeri Atamaniouk
@Gray,你是对的,我刚刚从源代码中检查了一下。但这使得任务更简单:无需子类化...只需取消队列中的所有未来任务即可。 - Valeri Atamaniouk
只需要说明可以将pool转换为ThreadPoolExecutor以实现此功能。 - pstanton
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接