无法制作具有大小限制的缓存线程池?

新手上路,请多包涵

似乎不可能制作一个缓存线程池,限制它可以创建的线程数。

以下是 static Executors.newCachedThreadPool 在标准 Java 库中的实现方式:

  public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

因此,使用该模板继续创建一个固定大小的缓存线程池:

 new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new SynchronusQueue<Runable>());

现在,如果您使用它并提交 3 个任务,一切都会好起来的。提交任何进一步的任务将导致拒绝执行异常。

试试这个:

 new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runable>());

将导致所有线程顺序执行。即,线程池永远不会创建多个线程来处理您的任务。

这是 ThreadPoolExecutor 的执行方法中的错误?或者这是故意的?或者还有其他方法吗?

编辑:我想要一些与缓存线程池完全一样的东西(它按需创建线程,然后在超时后杀死它们)但是它可以创建的线程数量有限制,并且一旦它有继续排队额外任务的能力达到其线程限制。根据 sjlee 的回应,这是不可能的。看看 execute() 方法 ThreadPoolExecutor 确实是不可能的。 I would need to subclass ThreadPoolExecutor and override execute() somewhat like SwingWorker does, but what SwingWorker does in its execute() 是一个完整的破解。

原文由 Matt Wonlaw 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 606
2 个回答

ThreadPoolExecutor 有以下几个关键行为,你的问题可以通过这些行为来解释。

提交任务时,

  1. 如果线程池没有达到核心大小,它会创建新的线程。
  2. 如果已达到核心大小并且没有空闲线程,它将对任务进行排队。
  3. 如果已达到核心大小,没有空闲线程,并且队列变满,它会创建新线程(直到达到最大大小)。
  4. 如果已达到最大大小,没有空闲线程,并且队列变满,则拒绝策略生效。

在第一个示例中,请注意 SynchronousQueue 的大小基本上为 0。因此,当您达到最大大小 (3) 时,拒绝策略就会启动 (#4)。

在第二个示例中,选择的队列是 LinkedBlockingQueue 具有无限大小。因此,您会陷入行为#2。

您不能真正修改缓存类型或固定类型,因为它们的行为几乎是完全确定的。

如果你想有一个有界和动态的线程池,你需要使用一个正的核心大小和最大大小以及一个有限大小的队列。例如,

 new ThreadPoolExecutor(10, // core size
    50, // max size
    10*60, // idle timeout
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<Runnable>(20)); // queue with a size

附录:这是一个相当古老的答案,当核心大小为 0 时,JDK 似乎改变了它的行为。从 JDK 1.6 开始,如果核心大小为 0 并且池中没有任何线程,则 ThreadPoolExecutor 将添加一个线程来执行该任务。因此,核心大小为 0 是上述规则的一个例外。感谢 史蒂夫 提醒 我注意这一点。

原文由 sjlee 发布,翻译遵循 CC BY-SA 4.0 许可协议

除非我错过了什么,否则原始问题的解决方案很简单。以下代码实现了原始海报所描述的所需行为。它将产生最多 5 个线程来处理无界队列,空闲线程将在 60 秒后终止。

 tp = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS,
                    new LinkedBlockingQueue<Runnable>());
tp.allowCoreThreadTimeOut(true);

原文由 user1046052 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题