ThreadPoolExecutor具有无限制队列而不创建新线程

时间:2013-03-18 20:02:34

标签: java multithreading threadpool threadpoolexecutor

我的ThreadPoolExecutor无法创建新主题。事实上,我写了一个有点hacky LinkedBlockingQueue,它将接受任何任务(即它是无限制的)但是调用一个额外的处理程序 - 在我的应用程序中发出警告跟踪池是落后的 - 这给了我非常明确的信息, TPE拒绝创建新线程,即使队列中有数千个条目。我的构造函数如下:

private final ExecutorService s3UploadPool = 
new ThreadPoolExecutor(1, 40, 1, TimeUnit.HOURS, unboundedLoggingQueue);

为什么不创建新线程?

3 个答案:

答案 0 :(得分:18)

this blog post

中介绍了这个问题
  

这种线程池的构造根本不会按预期工作。这是由于ThreadPoolExecutor中的逻辑,如果有失败向队列提供任务,则添加新线程。在我们的例子中,我们使用无界的LinkedBlockingQueue,我们总是可以向队列提供任务。它实际上意味着我们永远不会超过核心池大小并达到最大池大小。

如果您还需要将最小池大小与最大池大小分离,则必须进行一些扩展编码。我不知道Java库或Apache Commons中存在的解决方案。解决方案是创建一个知道TPE的耦合BlockingQueue,并且如果它知道TPE没有可用线程,则会不经意地拒绝任务,然后手动重新排队。链接帖子中有更详细的介绍。最终,您的构造将如下所示:

public static ExecutorService newScalingThreadPool(int min, int max, long keepAliveTime) {
   ScalingQueue queue = new ScalingQueue();
   ThreadPoolExecutor executor =
      new ScalingThreadPoolExecutor(min, max, keepAliveTime, TimeUnit.MILLISECONDS, queue);
   executor.setRejectedExecutionHandler(new ForceQueuePolicy());
   queue.setThreadPoolExecutor(executor);
   return executor;
}

然而,更简单地将corePoolSize设置为maxPoolSize并且不要担心这种废话。

答案 1 :(得分:4)

正如@djechlin所提到的,这是ThreadPoolExecutor定义的(令人惊讶的)行为的一部分。我相信我已经找到了一个关于这种行为的优雅解决方案,我在这里回答:

  

How to get the ThreadPoolExecutor to increase threads to max before queueing?

基本上,你扩展LinkedBlockingQueue使queue.offer(...)总是返回false,如果需要,它会向池中添加一个额外的线程。如果池已经处于最大线程并且它们都忙,则将调用RejectedExecutionHandler。然后是处理程序将put(...)放入队列。

在那里查看我的代码。

答案 2 :(得分:3)

这个问题有一个解决方法。请考虑以下实现:

int corePoolSize = 40;
int maximumPoolSize = 40;
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 
    60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
threadPoolExecutor.allowCoreThreadTimeOut(true);

通过将allowCoreThreadTimeOut()设置为true,允许池中的线程在指定的超时(本示例中为60秒)后终止。使用此解决方案,corePoolSize构造函数参数在实践中确定最大池大小,因为线程池将增长到corePoolSize,然后开始向队列添加作业。池可能永远不会变大,因为池在队列满之前不会产生新线程(假设LinkedBlockingQueue具有Integer.MAX_VALUE容量可能永远不会发生。因此,将maximumPoolSize设置为大于corePoolSize的值时,没有什么意义。

考虑:在超时到期后,线程池有0个空闲线程,这意味着在创建线程之前会有一些延迟(通常,你总是有corePoolSize个线程可用)。

更多细节可以在ThreadPoolExecutor的JavaDoc中找到。