我有以下代码:
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
中,并从队列中轮询以执行任务,因此应该没有死锁了吗?
答案 0 :(得分:3)
执行程序服务的正常行为是在池中的每个可用工作线程上启动任务,并将其他任务放入队列以等待工作线程可用。
您要做的是编写直到所有其他任务都开始才能完成的任务。由于您有10个工作人员,因此前10个任务每个都从一个工作人员开始....然后等待。前10个不能完成,因为它们正在等待其他任务开始,而其他任务也不能启动,因为执行者正在等待工人释放...直到前10个中的一个都不会发生任务完成。死锁。
您评论了
我认为threadPoolExecutor会将待处理的任务放入LinkedBlockingQueue中,并从队列中轮询以执行任务,因此应该没有死锁了吗?
所有任务都正确排队。问题在于任务排队后本身在做什么?请参阅上面的说明。
解决方案:
不要将您的任务设计为等待其他任务开始。 (从您的示例中尚不清楚为什么要执行此操作,但我怀疑这是否确实必要。)
如果必须等待其他任务开始,请增加线程池的大小,使其足够大以同时 运行所有任务。
答案 1 :(得分:1)
因为在“ latch.await();”上阻塞的每个任务,LinkedBlockingQueue <>中排队的任务将永远不会有运行的机会。造成僵局。您应该在每个任务中使用latch.countDown()。但是在主线程中运行闩锁。