我正在尝试使用 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
因为任务的数量超过了工作队列的大小。但是,我正在寻找的期望行为是让主线程阻塞,直到队列中有空间。实现这一目标的最佳方法是什么?
最佳答案
在一些非常狭窄的情况下,您可以实现一个 java.util.concurrent.RejectedExecutionHandler 来满足您的需要。
RejectedExecutionHandler block = new RejectedExecutionHandler() {
rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
executor.getQueue().put( r );
}
};
ThreadPoolExecutor pool = new ...
pool.setRejectedExecutionHandler(block);
现在。这是一个非常糟糕的主意,原因如下
- 它很容易出现死锁,因为池中的所有线程都可能在您放入队列中的东西可见之前就死了。通过设置合理的保持 Activity 时间来缓解此问题。
- 任务未按照您的 Executor 预期的方式包装。许多执行器实现在执行之前将它们的任务包装在某种跟踪对象中。看看你的来源。
- API 强烈反对通过 getQueue() 添加,并且在某些时候可能会被禁止。
几乎总是更好的策略是安装 ThreadPoolExecutor.CallerRunsPolicy,它将通过在调用 execute() 的线程上运行任务来限制您的应用程序。
但是,有时阻止策略及其所有固有风险确实是您想要的。我会说在这些条件下
- 你只有一个线程调用 execute()
- 您必须(或希望)有一个非常小的队列长度
- 您绝对需要限制运行此工作的线程数(通常是出于外部原因),而调用者运行策略会破坏这一点。
- 您的任务大小无法预测,因此如果池暂时忙于 4 个短任务并且您的一个线程调用 execute 被一个大任务卡住,调用者运行可能会导致饥饿。
所以,正如我所说。它很少需要,而且可能很危险,但你去吧。
祝你好运。
关于java - ThreadPoolExecutor 在队列满时阻塞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3446011/