在一个线程池中同时提交多个并行任务后,主线程应当采用哪些同步机制来感知所有子任务均已结束,并汇总每个任务的返回结果?
考察说明
考察对线程池任务执行完成状态的感知与结果收集机制的理解。
回答思路
- 【回答框架 1】可以使用Future对象。提交任务时返回Future,主线程对每个Future调用get()方法,该方法会阻塞直到对应任务完成并返回结果,从而依次等待并收集所有结果。
- 【回答框架 2】可以使用CountDownLatch或CyclicBarrier。初始化计数器为任务数量,每个任务完成后调用countDown(),主线程调用await()等待计数器归零,实现所有任务完成的同步。
- 【回答框架 3】可以使用ExecutorService的invokeAll()方法,该方法接收一批Callable任务,阻塞直到所有任务完成,返回一个List<Future>,每个Future已保证isDone()为true,可直接获取结果。
- 【回答框架 4】对于需要处理任意任务完成的情况,可使用CompletionService,它结合了Executor和BlockingQueue,通过take()方法按完成顺序获取Future,避免因最先完成的任务等待而降低效率。
- 【回答框架 5】使用CompletableFuture可以更灵活,通过allOf()静态方法组合多个异步任务,并可使用thenApply或join等回调方式在主线程或回调线程中收集结果。
- 【关键点 1】Future的get()会阻塞直至任务完成,用于逐一获取结果。
- 【关键点 2】invokeAll()一次性提交并阻塞至全部完成,返回结果列表。
- 【关键点 3】CompletionService按任务完成顺序返回Future,提升响应效率,适合先完成先处理的场景。
- 【关键点 4】CountDownLatch用于主线程等待所有任务执行完毕,不直接传递结果。
- 【关键点 5】CompletableFuture提供更丰富的组合与回调机制,可灵活处理多个异步结果。
- 【易错点 1】get()方法在不设置超时时可能长时间阻塞,若任务异常会抛出ExecutionException,需注意异常处理。
- 【易错点 2】CountDownLatch仅用于同步信号,结果仍需通过其他方式传递,且计数器不可复用。
- 【易错点 3】invokeAll()会等待所有任务结束,若某个任务长时间运行则整体等待时间较长。