ThreadPoolExecutor 策略

我正在尝试使用ThreadPoolExecutor来计划任务,但其策略遇到了一些问题。以下是其声明的行为:

  1. 如果运行的线程少于 corePoolSize 线程,则执行程序始终倾向于添加新线程而不是排队。
  2. 如果 corePoolSize 或更多线程正在运行,则执行程序始终倾向于对请求进行排队,而不是添加新线程。
  3. 如果请求无法排队,则会创建一个新线程,除非该线程超过 maxPoolSize,在这种情况下,任务将被拒绝。

我想要的行为是这样的:

  1. 同上
  2. 如果运行的池大小大于 corePoolSize 但小于最大值,则首选添加新线程而不是排队,并使用空闲线程而不是添加新线程。
  3. 同上

基本上,我不希望任何任务被拒绝;我希望它们在无限队列中排队。但我确实希望拥有最大PoolSize线程。如果我使用无界队列,它永远不会在达到coreSize后生成线程。如果我使用有界队列,它会拒绝任务。有什么办法可以解决这个问题吗?

我现在考虑的是在同步队列上运行 ThreadPoolExecutor,但不将任务直接提供给它 - 而是将它们提供给单独的无界 LinkedBlockingQueue。然后另一个线程从LinkedBlockingQueue馈送到执行器中,如果一个被拒绝,它只是重试,直到它不被拒绝。不过,这似乎是一种痛苦和一种黑客攻击 - 有没有一种更干净的方法可以做到这一点?


答案 1

可能没有必要根据请求对线程池进行微管理。

缓存线程池将重用空闲线程,同时还允许可能无限的并发线程。当然,这可能会导致在突发期间因上下文切换开销而导致性能失控。

Executors.newCachedThreadPool();

更好的选择是对线程总数设置限制,同时放弃确保首先使用空闲线程的概念。配置更改将是:

corePoolSize = maximumPoolSize = N;
allowCoreThreadTimeOut(true);
setKeepAliveTime(aReasonableTimeDuration, TimeUnit.SECONDS);

在这种情况下进行推理,如果执行器的线程数少于,则它一定不是很忙。如果系统不是很忙,那么启动新线程几乎没有坏处。这样做将导致您始终创建新工作人员(如果它低于允许的最大工作人员数)。只有当最大数量的工作线程“正在运行”时,才会为无所事事地等待任务的辅助角色提供任务。如果工作线程在没有任务的情况下等待,则允许其终止。对池大小使用合理的限制(毕竟,只有这么多 CPU)和相当大的超时(以防止线程不必要地终止),可能会看到所需的好处。corePoolSizeThreadPoolExecutoraReasonableTimeDuration

最后一个选项是黑客。基本上,内部用于确定队列是否具有容量。的自定义实现始终可以拒绝尝试。当任务失败到队列中时,它将尝试制作一个新的工作线程。如果无法创建新工作人员,则调用 a。此时,自定义可以强制 a 进入自定义 。ThreadPoolExecutorBlockingQueue.offerBlockingQueueofferThreadPoolExecutorofferRejectedExecutionHandlerRejectedExecutionHandlerputBlockingQueue

/** Hackish BlockingQueue Implementation tightly coupled to ThreadPoolexecutor implementation details. */
class ThreadPoolHackyBlockingQueue<T> implements BlockingQueue<T>, RejectedExecutionHandler {
    BlockingQueue<T> delegate;

    public boolean offer(T item) {
        return false;
    }

    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        delegate.put(r);
    }

    //.... delegate methods
}

答案 2

您的用例很常见,完全合法,不幸的是,比人们预期的要困难得多。有关背景信息,您可以阅读此讨论在此处找到指向解决方案(在线程中也提到)的指针。谢伊的解决方案工作正常。

一般来说,我会对无限的队列有点警惕;通常最好具有显式的传入流控制,该控制可以优雅地降级并调节当前/剩余工作的比例,以免使生产者或消费者不堪重负。


推荐