21

ThreadPoolExecutor无法创建新线程。事实上,我写了一个有点骇人听闻LinkedBlockingQueue的东西,它可以接受任何任务(即它是无界的),但调用了一个额外的处理程序——在我的应用程序中它会发出池在后面的警告跟踪——这给了我非常明确的信息,表明 TPE 拒绝创建即使队列中有数千个条目,也会有新线程。我的构造函数如下:

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

为什么它不创建新线程?

4

3 回答 3

24

这篇博文介绍了这个问题:

这种线程池的构造根本无法按预期工作。这是由于 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;
}

然而,更简单地设置并不corePoolSizemaxPoolSize担心这种废话。

于 2013-03-18T20:02:34.280 回答
5

正如@djechlin 所提到的,这是ThreadPoolExecutor. 我相信我已经找到了一个围绕这种行为的有点优雅的解决方案,我在这里的回答中展示了:

如何让 ThreadPoolExecutor 在排队之前将线程增加到最大值?

基本上,您可以扩展LinkedBlockingQueue使其始终返回 false queue.offer(...),如有必要,它将向池中添加额外的线程。如果池已经处于最大线程并且它们都忙,RejectedExecutionHandler则将被调用。然后是处理程序put(...)进入队列。

在那里查看我的代码。

于 2013-10-22T21:41:34.223 回答
5

有解决此问题的方法。考虑以下实现:

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,然后开始将作业添加到队列中。池很可能永远不会变得比这更大,因为在队列满之前池不会产生新线程(考虑到LinkedBlockingQueueInteger.MAX_VALUE容量可能永远不会发生)。因此,将maximumPoolSize值设置为大于 的意义不大corePoolSize

注意事项:线程池在超时后有 0 个空闲线程,这意味着在创建线程之前会有一些延迟(通常,您总是有corePoolSize可用的线程)。

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

于 2014-01-09T09:52:58.063 回答