Java 线程池执行器策略
我正试图使用ThreadPoolExecutor来安排任务,但它的策略遇到了一些问题。以下是它的声明行为:Java 线程池执行器策略,java,multithreading,concurrency,executor,blockingqueue,Java,Multithreading,Concurrency,Executor,Blockingqueue,我正试图使用ThreadPoolExecutor来安排任务,但它的策略遇到了一些问题。以下是它的声明行为: 如果正在运行的线程少于corePoolSize,则执行器总是倾向于添加新线程,而不是排队 如果corePoolSize或多个线程正在运行,那么执行器总是倾向于将请求排队,而不是添加新线程 如果请求无法排队,则会创建一个新线程,除非该线程将超过maximumPoolSize,在这种情况下,任务将被拒绝 我想要的行为是: 同上 如果运行的线程大于corePoolSize但小于maximumPo
我现在想的是在SynchronousQueue上运行ThreadPoolExecutor,但不是直接将任务提供给它,而是将它们提供给一个单独的无限LinkedBlockingQueue。然后,另一个线程从LinkedBlockingQueue馈送到执行器,如果一个线程被拒绝,它将再次尝试,直到它没有被拒绝为止。不过,这似乎是一种痛苦和一种攻击——有没有更干净的方法来做到这一点?只需设置
corePoolsize=maximumPoolSize
并使用一个无边界队列
在点列表中,1不包括2,因为corePoolSize
将始终小于或等于maximumPoolSize
编辑
在您想要的和TPE将提供给您的之间仍然存在一些不兼容的地方
如果您有一个无界队列,maximumPoolSize
将被忽略,因此,正如您所观察到的,将不会创建和使用超过corePoolSize
的线程
所以,同样,如果您使用一个无限队列获取
corePoolsize=maximumPoolSize
,您就得到了您想要的,不是吗 您会寻找更像缓存线程池的东西吗
可能不需要根据请求对线程池进行微管理 缓存线程池将重用空闲线程,同时还允许潜在的无限并发线程。当然,这可能会导致突发期间上下文切换开销导致性能失控
Executors.newCachedThreadPool();
更好的选择是对线程总数进行限制,同时放弃确保首先使用空闲线程的概念。配置更改将是:
corePoolSize = maximumPoolSize = N;
allowCoreThreadTimeOut(true);
setKeepAliveTime(aReasonableTimeDuration, TimeUnit.SECONDS);
在这种情况下,如果执行器的线程数小于corePoolSize
线程数,那么它一定不是很忙。如果系统不是很忙,那么启动一个新线程没有什么害处。执行此操作将导致ThreadPoolExecutor
始终创建一个新的工作线程(如果该工作线程数低于允许的最大工作线程数)。只有当最大数量的工人正在“运行”时,空闲等待任务的工人才会被分配任务。如果工作人员在没有任务的情况下等待aReasonableTimeDuration
,则允许其终止。使用合理的池大小限制(毕竟,只有这么多CPU)和合理的超时(防止线程不必要地终止),很可能会看到预期的好处
最后一个选择是草率的。基本上,ThreadPoolExecutor
在内部使用BlockingQueue.offer
来确定队列是否有容量。BlockingQueue
的自定义实现总是可以拒绝提供
尝试。当ThreadPoolExecutor
未能向队列提供任务时,它将尝试创建一个新的辅助进程。如果无法创建新工作进程,将调用RejectedExecutionHandler
。此时,自定义RejectedExecutionHandler
可能会强制将put
放入自定义BlockingQueue
/** 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
}
/**Hackish BlockingQueue实现与ThreadPoolexecutor实现细节紧密耦合*/
类ThreadPoolHackyBlockingQueue实现BlockingQueue,RejectedExecutionHandler{
阻塞队列委托;
公开发售(T项){
返回false;
}
public void rejectedExecution(可运行的r、线程池执行器执行器){
委托人。付诸表决(r);
}
//…委托方法
}
您的用例是常见的、完全合法的,不幸的是比预期的更难。对于背景信息,您可以阅读并找到指向解决方案的指针(也在线程中提到)。谢伊的解决方案很好用
一般来说,我会对无界队列有点担心;通常最好有显式的传入流控制,它可以优雅地降级,并调节当前/剩余工作的比率,以不压倒生产者或消费者。Oops,我写的并不是我想要的。我编辑了原始设置。设置corePoolsize=maximumPoolSize确实很接近,但我也使用allowCoreThreadTimeOut(false)和prestartAllCoreThreads()。