在 Java 中安排定期任务,避免在必要时创建新线程(如 CachedThreadPool)

Posted

技术标签:

【中文标题】在 Java 中安排定期任务,避免在必要时创建新线程(如 CachedThreadPool)【英文标题】:Schedule periodic tasks in Java, avoid creating new threads until necessary (like CachedThreadPool) 【发布时间】:2012-09-25 05:41:53 【问题描述】:

我有许多任务,我希望以不同的速率定期执行大多数任务。不过,有些任务可能会安排为同时执行。此外,一个任务可能需要在另一个任务当前正在执行时开始执行。

我还想通过为每个任务设置一个对象来自定义每个任务,该任务将在执行时对其进行操作。

通常,任务将在 2 到 30 分钟的周期内执行,大约需要 4-5 秒,有时执行时长达 30 秒。

我发现Executors.newSingleThreadedScheduledExecutor(ThreadFactory) 几乎正是我想要的,但如果一个新任务恰好被安排执行而另一个任务已经在执行,它可能会给我带来问题。这是因为 Executor 由单个执行线程备份。

替代方法是使用Executors.newScheduledThreadPool(corePoolSize, ThreadFactory),但这需要我在池中创建多个线程。我想避免在必要之前创建线程,例如,如果我有两个或多个任务由于它们的执行计划冲突而碰巧需要并行执行。

对于上述情况,Executors.newCachedThreadPool(ThreadFactory) 似乎可以执行我想要的操作,但是我无法安排我的任务。我认为缓存和调度执行器的组合最好,但我无法在 Java 中找到类似的东西。

您认为实现上述内容的最佳方式是什么?

【问题讨论】:

你可以看到Quartz Scheduler API。 空闲线程几乎没有成本。如果你只关心资源,我不会担心。 感谢您的回复。这听起来不错,而且我越来越倾向于在池中使用带有几个线程的 ScheduledExecutorService(必须研究最佳池大小)。我主要关心的是避免由于执行程序当前正在执行另一个任务而不得不等待执行的任务。 给你一些想法,你的 JVM 可以有大约 20 个线程来运行 HelloWorld。 ;) 是的,我知道这听起来可能是因为我正在应用过早的优化,但我将在项目的后期使用相当多的线程,并且我正在努力保持线程数低如果可能的话:) 【参考方案1】:

不是ScheduledThreadPoolExecutor.ScheduledThreadPoolExecutor(int):

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(0);

你需要什么? 0corePoolSize

corePoolSize - 保留在池中的线​​程数,即使它们是空闲的,除非设置了allowCoreThreadTimeOut

【讨论】:

不确定:“此外,将 corePoolSize 设置为零或使用 allowCoreThreadTimeOut 几乎不是一个好主意,因为一旦它们有资格运行,这可能会使池没有线程来处理任务。 " @assylias:+1,很好。但这仅意味着一旦任务符合条件,执行者将不得不启动新线程,这需要时间。如果这是唯一的问题,那么 OP 似乎可以忍受(他想要尽可能少的线程并且没有空闲)。我们会看到,但谢谢! 感谢您的回复。我不介意在池中有一两个线程并空闲。我更关心的是确保任务按计划执行,即使当前正在执行另一个任务。此外,在不使用单个调度执行器时找到正确的池大小也是一个问题。 @veroslav - 你不能同时拥有它。如果池中没有剩余线程,则无法在不创建新线程的情况下将新任务分派到线程上。 @Martin:你是对的,这很有意义。我只需要找到一个合适的线程池大小并完成它。感谢大家发表的所有想法和建议,它们很有帮助!【参考方案2】:

我猜你将无法使用 ScheduledExecutor 做到这一点,因为它使用 DelayedWorkQueue 而 newCachedThreadPool 使用 ThreadPoolExecutor SynchronousQueue 作为工作队列。

所以你不能改变 ScheduledThreadPoolExecutor 的实现来像那样行事。

【讨论】:

感谢您的回复。这似乎是正确的,如果我必须在两者之间做出选择,我将选择具有适当线程池大小的 ScheduledExecutor,因为它极大地简化了任务的调度,这是我目前的主要优先事项。 等待线程不会对您造成太大伤害,因为它们不会占用任何处理器空间。它们只会消耗堆空间,因此您可以为ScheduledExecutor 保留大量计数。 很高兴知道,空闲线程使用的资源是我主要关心的问题之一,因为我认为它们正在“等待”某些“run()”方法准备执行。很高兴听到事实并非如此。

以上是关于在 Java 中安排定期任务,避免在必要时创建新线程(如 CachedThreadPool)的主要内容,如果未能解决你的问题,请参考以下文章

如何停止在 java.util.Timer 类中安排的任务

如何在PHP中安排MySQL数据库的定期更新? [重复]

在后台任务中安排通知

在 Windows Server 2008 R2 中安排任务

在 Rails 中安排一个 ActiveJob

通过 R 运行 .vbs 脚本,在任务计划程序中安排