我有一个使用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创建了比我想要的更多的池。这是一个潜在的问题,因为我正在尝试提高低功耗黑匣子计算机的性能,并且正在尝试减少额外的工作。

最佳答案

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

javadoc告诉我们:


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


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


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


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

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

10-07 23:01