对正常任务和计划任务使用单独的线程池

Using separate thread pools for normal and scheduled tasks

假设我已经有一个应用程序范围的 ThreadPoolExecutor,现在我还需要一个 ScheduledExecutorService。我是否应该将实现更改为 ScheduledThreadPoolExecutor 并将其用于计划任务和普通任务?或者我应该为普通任务设置一个 ThreadPoolExecutor,为计划任务设置一个单独的 ScheduledThreadPoolExecutor?将 ScheduledThreadPoolExecutor 用于普通任务是个好主意,还是它的实现中有什么东西让它只对计划任务有用?

我的想法是,单个 ScheduledThreadPoolExecutor 将允许最佳线程使用,但如果我们有许多计划任务而普通任务很少,则它会增加饥饿的风险,反之亦然。

关于更多上下文,我有一个旧代码库,它仍然使用 java.util.Timer 执行计划任务,并使用应用程序范围的 ThreadPoolExecutor 执行普通任务。由于 Timer 是单线程的,我们的 TimerTasks 通常会在 Timer 执行它们后立即将计算转移到线程池,以免延迟进一步的 TimerTasks。沿着这些线的东西:

timer.schedule(new TimerTask() {
  public void run() {
    executor.execute(this::performWork);
  }
}, 1000);

到目前为止,我们将重构从 Timer 推迟到 ScheduledThreadPoolExecutor,但直到现在我才意识到,当对所有类型的任务使用单个线程池时,我们可以消除上述结构.

出于两个原因,我建议使用两个单独的池。第一个原因是,我发现从应用程序的角度来看,如果池是不同的,则调整它们会更容易。预测计划任务和一次性任务所需的线程数可能比组合工作负载更容易。 第二个原因来自API:

While this class inherits from ThreadPoolExecutor, a few of the inherited tuning methods are not useful for it. In particular, because it acts as a fixed-sized pool using corePoolSize threads and an unbounded queue, adjustments to maximumPoolSize have no useful effect. Additionally, it is almost never a good idea to set corePoolSize to zero or use allowCoreThreadTimeOut because this may leave the pool without threads to handle tasks once they become eligible to run.

换句话说,它的行为与常规的 ThreadPoolExecutor 不同,调整工作可能会产生令人惊讶的效果,包括饥饿。