java - ThreadPoolExecutor 在队列满时阻塞?

标签 java multithreading concurrency executorservice executor

我正在尝试使用 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/

相关文章:

unit-testing - 在 go 中测试连接的正确方法

linux - Golang调度器之谜: Linux vs Mac OS X

java - Runtime.getRuntime().exec 可以是类路径资源吗?

java - 在嵌套类中实现的比较器接口(interface)

python - python 3中的thread.start_new_thread发生了什么

java - 如何强制 Hibernate 对开始分页的同一数据集进行分页?

multithreading - Javafx从线程Java 8更新UI

java - 文件上传到 postgres 数据库

java - 如何记录契约(Contract)最后(通过 jaxb schemagen)web 服务?

concurrency - Go webcrawler 在检查大约 2000 个 url 后挂起