Java 执行器中无界队列的用例是什么?

What is the use case for unbounded queue in Java Executors?

Executors 来自 Java 的工厂使用无界待处理任务队列。例如,Executors.newFixedThreadPool使用new LinkedBlockingQueue,它没有接受任务的限制。

public static ExecutorService newFixedThreadPool(int nThreads) {
  return new ThreadPoolExecutor(nThreads, nThreads,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>());
}

当新任务到达并且没有可用线程时,它会进入队列。任务可以无限期地添加到队列中,导致 OutOfMemoryError.

实际使用这种方法的场景是什么?为什么 Java 创作者不使用有界队列?我无法想象无界比有界更好的场景,但我可能会遗漏一些东西。有人可以提供一个体面的解释吗?最好!

可以reject tasks by using ArrayBlockingQueue(有界阻塞队列)

final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
executorService = new ThreadPoolExecutor(n, n,
    0L, TimeUnit.MILLISECONDS,
    queue);

Code above is equivalent to Executors.newFixedThreadPool(n), however instead of default unlimited LinkedBlockingQueue we use ArrayBlockingQueue with fixed capacity of 100. This means that if 100 tasks are already queued (and n being executed), new task will be rejected with RejectedExecutionException.

这是默认方法,用户可以选择更改为有界队列。

现在您的问题可能是为什么这是默认值?

有界队列其实更难处理,队列满了怎么办?你丢下任务不接?您抛出异常并使整个过程失败?那不是 OOM 的情况吗?所以所有这些都是需要接受大量长 运行 任务的用户做出的决定,而不是默认的 Java 用户。

无界队列的一个用例可能只是当您只期望少量 运行 并发请求但您不知道到底有多少或者您可以在您的不同阶段实施背压应用程序喜欢限制您的 API 请求。

Tasks can be added to the queue indefinitely causing OutOfMemoryError

没有。队列并不是真正的unbouned,对于一个无界的LinkedBlockingQueue,它的capacityInteger.MAX_VALUE(2147483647)。当space、RejectedExecutionHandler will handle new arrival tasks. And the default handler is AbortPolicy不够时,会直接中止新任务。

I can't imagine a scenario when unbounded is better the bounded

用户可能不关心队列大小,或者他们只是不想限制缓存的任务。

如果您确实关心它,可以使用自定义构造器创建一个 ThreadPoolExecutor

既然你问的是 "use case",很简单:每次你有很多你想要最终完成的单一任务。假设您想下载数千个文件?为每个创建一个下载任务,提交到ExecutorService,等待终止。由于您不再添加任何内容,因此任务最终将完成,并且没有理由限制。