我有一个使用 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创建了比我想要的更多的池。这是一个潜在的问题,因为我正在尝试在低功率黑匣子计算机上提高性能,并且正在尝试减少额外的工作。
答案 0 :(得分:4)
对于您选择的队列类的功能/行为,您似乎有一个误解。相反,该队列不是未绑定或未阻塞。
javadoc告诉我们:
在执行器已关闭时,并且在执行器对最大线程数和工作队列容量都使用了有限范围时,将拒绝在方法execute(java.lang.Runnable)中提交的新任务。 ,并且已饱和。
但更重要的是,SynchronousQueue的javadoc表示:
阻塞队列,其中每个插入操作必须等待另一个线程进行相应的删除操作,反之亦然。
当您将20个长期运行的任务输入其中时,每个任务都会进入一个线程。当#21进入时它们仍在运行时,该池已被完全使用,并且队列立即显示:“我也已满”。一切都已饱和,不再接受新工作。
解决方案:选择其他队列。