为什么 invokeAll 在池大小有限的执行器服务中失败



我有一个类,它使用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);

但是,如果我进行调用并且查找大于可用池大小,则会失败。但我不明白这一点,因为池大小只指定可以使用的最大线程数,它使用同步队列而不是阻塞队列,所以为什么不将额外的查找添加到队列中。

如果我只是更改为最大池大小整数.MAX_值

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

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

对于您选择的队列类的功能/行为,您似乎存在误解。相反,该队列不会解除绑定或未阻塞。

javadoc告诉我们:

当执行器关闭时,以及在执行

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

但更重要的是,SyncQueue 的 javadoc 说:

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

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

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

相关内容

  • 没有找到相关文章

最新更新