本文介绍了队列满时线程池执行器阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to execute lots of tasks using a ThreadPoolExecutor. Below is a hypothetical example:

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,因为任务数量超过了工作队列的大小.但是,我正在寻找的所需行为是让主线程阻塞,直到队列中有空间为止.实现此目的的最佳方法是什么?

The problem is that I quickly get a java.util.concurrent.RejectedExecutionException since the number of tasks exceeds the size of the work queue. However, the desired behavior I am looking for is to have the main thread block until there is room in the queue. What is the best way to accomplish this?

推荐答案

在一些非常狭窄的情况下,您可以实现一个 java.util.concurrent.RejectedExecutionHandler 来满足您的需求.

In some very narrow circumstances, you can implement a java.util.concurrent.RejectedExecutionHandler that does what you need.

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() 的线程上运行任务来限制您的应用程序.

A almost-always-better strategy is to install ThreadPoolExecutor.CallerRunsPolicy which will throttle your app by running the task on the thread which is calling execute().

然而,有时阻塞策略及其所有固有风险确实是您想要的.我会说在这些条件下

However, sometimes a blocking strategy, with all its inherent risks, is really what you want. I'd say under these conditions

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

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

So, as I say. It's rarely needed and can be dangerous, but there you go.

祝你好运.

这篇关于队列满时线程池执行器阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-30 04:56