为什么InvokeAll在ExecutorService池大小有限的情况下失败

时间:2019-06-18 07:52:57

标签: java executorservice java.util.concurrent

我有一个使用 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 ,所以为什么不添加额外的查询呢?进入队列。

如果我只是更改为最大池大小,则为Integer.MAX_VALUE

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

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

1 个答案:

答案 0 :(得分:4)

对于您选择的队列类的功能/行为,您似乎有一个误解。相反,该队列不是未绑定或未阻塞。

javadoc告诉我们:

  

在执行器已关闭时,并且在执行器对最大线程数和工作队列容量都使用了有限范围时,将拒绝在方法execute(java.lang.Runnable)中提交的新任务。 ,并且已饱和。

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

  

阻塞队列,其中每个插入操作必须等待另一个线程进行相应的删除操作,反之亦然。

当您将20个长期运行的任务输入其中时,每个任务都会进入一个线程。当#21进入时它们仍在运行时,该池已被完全使用,并且队列立即显示:“我也已满”。一切都已饱和,不再接受新工作。

解决方案:选择其他队列。