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

时间:2018-12-06 00:18:53

标签: java concurrency java.util.concurrent

我有以下代码:

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中,并从队列中轮询以执行任务,因此应该没有死锁了吗?

2 个答案:

答案 0 :(得分:3)

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

您要做的是编写直到所有其他任务都开始才能完成的任务。由于您有10个工作人员,因此前10个任务每个都从一个工作人员开始....然后等待。前10个不能完成,因为它们正在等待其他任务开始,而其他任务也不能启动,因为执行者正在等待工人释放...直到前10个中的一个都不会发生任务完成。死锁。


您评论了

  

我认为threadPoolExecutor会将待处理的任务放入LinkedBlockingQueue中,并从队列中轮询以执行任务,因此应该没有死锁了吗?

所有任务都正确排队。问题在于任务排队后本身在做什么?请参阅上面的说明。


解决方案:

  • 不要将您的任务设计为等待其他任务开始。 (从您的示例中尚不清楚为什么要执行此操作,但我怀疑这是否确实必要。)

  • 如果必须等待其他任务开始,请增加线程池的大小,使其足够大以同时 运行所有任务。

答案 1 :(得分:1)

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