如何判断线程池任务已执行完?

线程池的使用并不复杂,麻烦的是如何判断线程池中的任务已经全部执行完了?因为我们要等所有任务都执行完之后,才能进行数据的组装和返回,所以接下来,我们就来看如何判断线程中的任务是否已经全部执行完?

如何判断线程池任务已执行完?

文章插图
无论是在项目开发中,还是在面试中过程中,总会被问到或使用到并发编程来完成项目中的某个功能 。
例如某个复杂的查询,无法使用一个查询语句来完成此功能,此时我们就需要执行多个查询语句,然后再将各自查询的结果,组装之后返回给前端了,那么这种场景下,我们就必须使用线程池来进行并发查询了 。
PS:磊哥做的最复杂的查询,总共关联了 21 张表,在和产品及需求方的沟通多次沟通下,才将查询的业务从 21 张表,降到了至少要查询 12 张表(非常难搞),那么这种场景下是无法使用一个查询语句来实现的,那么并发查询是必须要给安排上的 。
1、需求分析线程池的使用并不复杂,麻烦的是如何判断线程池中的任务已经全部执行完了?因为我们要等所有任务都执行完之后,才能进行数据的组装和返回,所以接下来,我们就来看如何判断线程中的任务是否已经全部执行完?
2、实现概述判断线程池中的任务是否执行完的方法有很多,比如以下几个:
  • 使用 getCompletedTaskCount() 统计已经执行完的任务,和 getTaskCount() 线程池的总任务进行对比,如果相等则说明线程池的任务执行完了,否则既未执行完 。
  • 使用 FutureTask 等待所有任务执行完,线程池的任务就执行完了 。
  • 使用 CountDownLatch 或 CyclicBarrier 等待所有线程都执行完之后,再执行后续流程 。
具体实现代码如下 。
3、具体实现(1)统计完成任务数通过判断线程池中的计划执行任务数和已完成任务数,来判断线程池是否已经全部执行完,如果计划执行任务数=已完成任务数,那么线程池的任务就全部执行完了,否则就未执行完 。示例代码如下:
private static void isCompletedByTaskCount(ThreadPoolExecutor threadPool) {while (threadPool.getTaskCount() != threadPool.getCompletedTaskCount()) {}}以上程序执行结果如下:
如何判断线程池任务已执行完?

文章插图
方法说明
  • getTaskCount():返回计划执行的任务总数 。由于任务和线程的状态可能在计算过程中动态变化,因此返回的值只是一个近似值 。
  • getCompletedTaskCount():返回完成执行任务的总数 。因为任务和线程的状态可能在计算过程中动态地改变,所以返回的值只是一个近似值,但是在连续的调用中并不会减少 。
缺点分析此判断方法的缺点是 getTaskCount() 和 getCompletedTaskCount() 返回的是一个近似值,因为线程池中的任务和线程的状态可能在计算过程中动态变化,所以它们两个返回的都是一个近似值 。
(2)FutureTaskFutrueTask 的优势是任务判断精准,调用每个 FutrueTask 的 get 方法就是等待该任务执行完,如下代码所示:
import JAVA.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;/** * 使用 FutrueTask 等待线程池执行完全部任务 */public class FutureTaskDemo {public static void mAIn(String[] args) throws ExecutionException, InterruptedException {// 创建一个固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 创建任务FutureTask<Integer> task1 = new FutureTask<>(() -> {System.out.println("Task 1 start");Thread.sleep(2000);System.out.println("Task 1 end");return 1;});FutureTask<Integer> task2 = new FutureTask<>(() -> {System.out.println("Task 2 start");Thread.sleep(3000);System.out.println("Task 2 end");return 2;});FutureTask<Integer> task3 = new FutureTask<>(() -> {System.out.println("Task 3 start");Thread.sleep(1500);System.out.println("Task 3 end");return 3;});// 提交三个任务给线程池executor.submit(task1);executor.submit(task2);executor.submit(task3);// 等待所有任务执行完毕并获取结果int result1 = task1.get();int result2 = task2.get();int result3 = task3.get();System.out.println("Do main thread.");}}以上程序的执行结果如下:
如何判断线程池任务已执行完?


推荐阅读