ThreadPoolExecutor 在其队列已满时阻塞?

新手上路,请多包涵

我正在尝试使用 ThreadPoolExecutor 执行大量任务。下面是一个假设的例子:

 def workQueue = new ArrayBlockingQueue<Runnable>(3, false)
def threadPoolExecutor = new ThreadPoolExecutor(3, 3, 1L, TimeUnit.HOURS, workQueue)
for(int i = 0; i < 100000; i++)
    threadPoolExecutor.execute(runnable)

问题是我很快得到一个 java.util.concurrent.RejectedExecutionException 因为任务数量超过了工作队列的大小。但是,我正在寻找的理想行为是让主线程阻塞,直到队列中有空间为止。完成此任务的最佳方法是什么?

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

阅读 485
1 个回答

在一些非常狭窄的情况下,您可以实现一个 java.util.concurrent.RejectedExecutionHandler 来执行您需要的操作。

 RejectedExecutionHandler block = new RejectedExecutionHandler() {
  rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
     executor.getQueue().put( r );
  }
};

ThreadPoolExecutor pool = new ...
pool.setRejectedExecutionHandler(block);

现在。由于以下原因,这是 一个非常糟糕的主意

  • 它很容易死锁,因为池中的所有线程都可能在你放入队列的东西可见之前就死掉了。通过设置合理的保持活动时间来缓解这种情况。
  • 任务没有按照您的 Executor 期望的方式包装。许多执行器实现在执行前将它们的任务包装在某种跟踪对象中。看看你的来源。
  • API 强烈反对通过 getQueue() 添加,有时可能会被禁止。

几乎总是更好的策略是安装 ThreadPoolExecutor.CallerRunsPolicy,它将通过在调用 execute() 的线程上运行任务来限制您的应用程序。

然而,有时一个具有所有固有风险的阻止策略确实是您想要的。我会说在这些条件下

  • 您只有一个线程调用 execute()
  • 你必须(或想要)有一个非常小的队列长度
  • 您绝对需要限制运行此工作的线程数(通常是出于外部原因),而调用者运行策略会破坏它。
  • 你的任务是不可预测的大小,所以如果池暂时忙于 4 个短任务并且你的一个线程调用 execute 被一个大任务卡住,调用者运行可能会导致饥饿。

所以,正如我所说。它很少需要并且可能很危险,但你去吧。

祝你好运。

原文由 Darren Gilroy 发布,翻译遵循 CC BY-SA 2.5 许可协议

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