为什么 invokeAll 会因池大小有限的 ExecutorService 而失败

Why does invokeAll fail with ExecutorService with limited pool size

我有一个 class,它使用 ExecutorService 来发出 url 请求,这样它们就可以 运行 并行,并且我将其限制为最大池大小 20

private static ExecutorService getCachedPool(ThreadFactory threadFactory)
{
    return new ThreadPoolExecutor(20, 20,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(),
            threadFactory);
}

不过我是这样使用的:

List<Future<ArtistCoverImage>> results = ArtistArtworkOnlineLookup.getExecutorService()
    .invokeAll(lookups);

但是如果我进行调用并且查找大于可用池大小,它将失败。但我不明白这一点,因为池大小仅指定可以使用的最大线程,它使用 SynchronousQueue 而不是 BlockingQueue 所以为什么是' t 刚刚添加到队列中的额外查找。

如果我简单地更改为最大池大小 Integer.MAX_VALUE

private static ExecutorService getCachedPool(ThreadFactory threadFactory)
    {
        return new ThreadPoolExecutor(20, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(),
                threadFactory);
    }

没有问题,但是我创建的池比我想要的要多。这是一个潜在的问题,因为我正在尝试提高低功率黑匣子机器的性能,并且正在尝试尽量减少额外的工作。

您这边似乎对您选择的 class 队列的 capability/behavior 有误解。相反,该队列不是未绑定或未阻塞。

javadoc告诉我们:

New tasks submitted in method execute(java.lang.Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated.

但更重要的是,SynchronousQueue 的 javadoc 表示:

A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa.

当您向其中输入 20 个长 运行 任务时,每个任务都会进入一个线程。当#21进来的时候都还运行,pool用满了,queue立马说:"I am full, too"。一切都饱和了,新工作不再被接受。

解决方案:选择不同类型的队列。