【问题标题】:How to reset a thread pool efficiently如何有效地重置线程池
【发布时间】:2013-04-21 13:04:33
【问题描述】:

我正在使用线程池来使多个不重要的任务排队并(可能)执行,但是我需要能够轻松取消所有排队和正在执行的任务,并从头开始一个新队列。

即:

// 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);

我忽略了对“清除”的调用,因为这很慢,而且队列稍后会被池清理。我知道当前执行的任务可能不会因此而终止,这对我有用。

谢谢。

【问题讨论】:

  • 如果您已经回答了您的问题,请将答案放在答案部分,而不是问题。
  • @NicolBolas 感谢您的反对和谴责。我使用了一个很有帮助的海报答案,但想澄清我的用法,以防将来对人们有所帮助。我不想通过用我从别人那里复制的东西来自我回答来为自己争取所有的荣耀。你们中的一些人太珍贵了,这确实有损于使用网络上最有用的资源。为什么不将注意力转向真正需要帮助的帖子,而不是关注已经解决的好问题。祝你有美好的一天。
  • 我不想通过用我从别人那里复制的东西自我回答来为自己争取所有的荣耀。”然后发布您的答案并点赞/接受他们的。这不是关于“声称荣耀”;这是关于适当的组织。问题在顶部,答案在“答案”部分。这就是使它成为“有用资源”的原因。回答你自己的问题很好。 “为什么不把注意力转向真正需要帮助的帖子,而不是关注已经解决的好问题。”当你提出答案时,它就不再是一个“好问题”了i> 在里面。因此投反对票。
  • 不同人的不同笔画。

标签: java concurrency threadpool


【解决方案1】:

您可以监控从提交任务获得的所有Futures 和所有cancel(),这将允许您重新使用线程池而无需重新创建。但是,我怀疑您会获得太多额外的效率。

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

【讨论】:

  • 是的,我知道关闭和取消不一定会停止正在运行的任务/线程。当然,在任务执行之前取消任务会比终止和重新创建所有内容(包括线程、队列等)更有效?
  • 效率更高,但我只想说一点。这取决于您执行此操作的频率。我的意思是您需要添加代码来管理正在运行的任务列表,这也是开销。我怀疑当你用新的方式计时时,你不会看到显着的差异。您选择的答案完全错误了 2 次,直到我更正它并从一开始就提出了该机制。但是哦,好吧@pstanton。
  • +1 并感谢答案,ThreadPoolExecutor.getQueue 意味着我不必管理列表。谢谢您的帮助。不知道为什么有人不赞成你的答案,我讨厌人们这样做而不发表评论......
【解决方案2】:

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

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

【讨论】:

  • FutureExecutorService 内部的一个内部包装器。你永远不会自己实现Future。这样做 'cancel(...)` 不会会中断相关线程。
  • 不,@Valeri 也不是这样。这些仍将被视为RunnableFutureTask 仅由并发类创建。
  • @Gray 我不明白你为什么不能创建FutureTaskdocs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/…
  • 您可以创建它@Valeri,但是当您将其提交到线程池时,它会将您的任务包装在另一个线程池中。这就是它的工作方式。您不提交FutureFutureTask。您提交RunnableCallable。在调试器中查看submit(...) 方法代码。
  • @Gray,你是对的,我刚刚从源代码中检查过。但这使任务更简单:无需子类化......只需从队列中取消所有期货。
猜你喜欢
  • 2011-08-26
  • 2012-11-21
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2011-12-05
相关资源
最近更新 更多