当线程数少于 invokeAll() 的任务数时会发生什么?

What will happen when there are less threads than number of tasks for invokeAll()?

我有以下代码:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                                                10, // corePoolSize
                                                10, // maximumPoolSize
                                                10, // keepAliveTime
                                                TimeUnit.SECONDS, 
                                                new LinkedBlockingQueue<>()
                                        );

final List<Callable<MyResponse>> tasks = new ArrayList<>();
final CountDownLatch latch = new CountDownLatch(concurrency);

for (int i = 0; i < 50; i++) {
    tasks.add(() -> {
        latch.countDown();
        latch.await();

        return getResponse(); // Returns a MyResponse object.
    });
}

final List<Future<ThrottleResponse>> futures = threadPoolExecutor.invokeAll(tasks);

有 50 个任务,但只有 10 个线程可用。根据我的测试结果,代码永远需要运行,我不明白。

invokeAll 方法发生了什么变化?这段代码中是否存在死锁,为什么?我认为 threadPoolExecutor 会将未决任务放入 LinkedBlockingQueue 并从队列中轮询以执行任务,所以应该没有死锁吧?

因为每个任务都在 "latch.await();" 上阻塞,LinkedBlockingQueue<> 中的排队任务将永远没有机会 运行。这造成了僵局。您应该在每个任务中使用 latch.countDown()。但是 latch.await() 在主线程中。

执行程序服务的正常行为是在池中的每个可用工作人员上启动任务,并将任何其他工作人员放入队列以等待工作人员可用。

您所做的是编写在所有其他任务开始之前不会完成的任务。由于您有 10 个工人,前 10 个任务每个都从一个工人开始……然后等待。前 10 个无法完成,因为他们正在等待其他任务开始,而其他任务无法开始,因为执行者正在等待一个工人空闲......直到前 10 个中的一个才会发生任务完成。死锁。


您发表评论:

I think the threadPoolExecutor would put pending tasks in the LinkedBlockingQueue and poll from the queue to execute the tasks, so there should be no dead lock right?

所有任务都正确排队。问题在于任务排队后自己在做什么;见上面的解释。


解决方案:

  • 不要将您的任务设计为等待其他任务开始。 (从你的例子中不清楚你为什么这样做,但我怀疑这是否真的有必要。)

  • 如果您必须等待其他任务启动,请增加线程池大小,使其足以运行所有任务同时[=32] =].