首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ThreadPoolExecutor政策

ThreadPoolExecutor政策
EN

Stack Overflow用户
提问于 2010-08-05 21:35:53
回答 4查看 6.3K关注 0票数 13

我试图使用ThreadPoolExecutor来调度任务,但是它的策略遇到了一些问题。以下是它声明的行为:

  1. 如果运行的线程少于corePoolSize线程,则执行器总是更喜欢添加新线程而不是排队。
  2. 如果corePoolSize或更多线程正在运行,执行器总是更喜欢排队请求,而不是添加新线程。
  3. 如果请求不能排队,将创建一个新线程,除非这将超过maximumPoolSize,在这种情况下,任务将被拒绝。

我想要的行为是:

  1. 与上述相同
  2. 如果运行的线程超过corePoolSize,但小于maximumPoolSize线程,则更喜欢添加新线程而不是队列,使用空闲线程而不是添加新线程。
  3. 与上述相同

基本上,我不希望任何任务被拒绝;我希望它们在一个无界队列中排队。但我确实想拥有最多的maximumPoolSize线程。如果我使用一个无界队列,它在访问coreSize之后就不会生成线程。如果我使用有界队列,它会拒绝任务。有办法绕过这件事吗?

我现在想的是在一个ThreadPoolExecutor上运行SynchronousQueue,而不是直接将任务提供给它,而是将它们提供给一个单独的、无界的LinkedBlockingQueue。然后,另一个线程从LinkedBlockingQueue输入到执行器,如果一个线程被拒绝,它只需再试一次,直到未被拒绝。这似乎是一种痛苦和一些黑客,尽管-有一个更干净的方法来做到这一点吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-08-06 08:01:50

您的用例是常见的,完全合法,不幸的是,它比人们预期的更困难。对于背景信息,您可以阅读这一讨论并找到指向解决方案的指针(在线程中也提到) 这里。谢伊的解决方案很好。

通常,我会对无界队列有点警惕;通常最好有显式的传入流控制,这种控制会优雅地降低,并调节当前/剩余工作的比率,而不会压倒生产者或消费者。

票数 1
EN

Stack Overflow用户

发布于 2010-08-06 06:01:49

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

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

代码语言:javascript
复制
Executors.newCachedThreadPool();

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

代码语言:javascript
复制
corePoolSize = maximumPoolSize = N;
allowCoreThreadTimeOut(true);
setKeepAliveTime(aReasonableTimeDuration, TimeUnit.SECONDS);

如果执行器的线程少于corePoolSize线程,则对此方案的推理不能太忙。如果系统不是很忙,那么纺出一个新线程几乎没有什么害处。这样做将导致ThreadPoolExecutor始终创建一个新的工作人员,如果它低于允许的最大工人数。只有当最大数量的工作人员在“运行”时,才会给空闲等待任务的工人分配任务。如果工作人员在没有任务的情况下等待aReasonableTimeDuration,则允许它终止。使用池大小的合理限制(毕竟,只有这么多CPU)和相当大的超时(以防止线程不必要地终止),可能会看到所需的好处。

最后一种选择是冷嘲热讽。基本上,ThreadPoolExecutor内部使用BlockingQueue.offer来确定队列是否具有容量。BlockingQueue的自定义实现总是可以拒绝offer尝试。当ThreadPoolExecutor无法将任务放到队列中时,它将尝试创建一个新的工作人员。如果无法创建新员工,则将调用RejectedExecutionHandler。此时,自定义RejectedExecutionHandler可以强制put进入自定义BlockingQueue

代码语言:javascript
复制
/** 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
}
票数 4
EN

Stack Overflow用户

发布于 2010-08-05 21:41:04

只需设置corePoolsize = maximumPoolSize并使用无界队列?

在你的点数列表中,1不包括2,因为corePoolSize总是小于或等于maximumPoolSize

编辑

在你想要的东西和TPE会提供给你的东西之间仍然有一些不相容的东西。

如果您有一个无界队列,maximumPoolSize就会被忽略,因此,正如您所观察到的,将只创建和使用corePoolSize线程。

所以,再次,如果您使用一个无限制队列的corePoolsize = maximumPoolSize,您就有您想要的了,不是吗?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3419380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档