1、使用 isTerminated 方法判断
2、使用 getCompletedTaskCount方法判断
3、使用CountDownLatch判断
4、使用 CyclicBarrier判断

一、isTerminated方法判断

我们可以利用线程池的终止状态(TERMINATED)来判断线程池的任务是否已经全部执行完,但想要线程池的状态发生改变,我们就需要调用线程池的shutdown方法,不然线程池一直会处于RUNNING 运行状态

缺点:需要先手动关闭线程池调用shutdown等方法,然后再通过isTerminated方法来判断。

private static void isCompleted(ThreadPoolExecutor threadPool) {
    threadPool.shutdown();//1、必须先手动关闭线程池
    while (!threadPool.isTerminated()) {
    	//2、如果没有执行完就一直循环
    }
}

二、getCompletedTaskCount

我们可以通过判断线程池中的计划执行任务数和已完成任务数,来判断线程池是否已经全部执行完,如果计划执行任务数=已完成任务数,那么线程池的任务就全部执行完了,否则就未执行完

//getCompletedTaskCount 实现方式判断线程池的所有任务是否执行完
private static void isCompletedByTaskCount(ThreadPoolExecutor threadPool) {
    while (threadPool.getTaskCount() != threadPool.getCompletedTaskCount()) {

    }
}

方法说明

1、getTaskCount():返回计划执行的任务总数。由于任务和线程的状态可能在计算过程中动态变化,因此返回的值只是一个近似值。
2、getCompletedTaskCount():返回完成执行任务的总数。因为任务和线程的状态可能在计算过程中动态地改变,所以返回的值只是一个近似值,但是在连续的调用中并不会减少。

优缺点分析

此实现方法的优点是无需关闭线程池。 它的缺点是getTaskCount() 和getCompletedTaskCount(),返回的是一个近似值,因为线程池中的任务和线程的状态可能在计算过程中动态变化,所以它们两个返回的都是一个近似值。

三、CountDownLatch

CountDownLatch 可以理解为一个计数器,我们创建了一个包含 N 个任务的计数器,每个任务执行完计数器 -1,直到计数器减为 0 时,说明所有的任务都执行完了

核心代码:

//在主线程定义线程计数器的总数
1、CountDownLatch countDownLatch = new CountDownLatch(taskCount);
2、countDownLatch.countDown();//在子线程完成减一的操作
3、countDownLatch.await();//主线程阻塞等待,当线程计数器值为0时,表示线程执行完毕

优缺点分析

CountDownLatch 写法很优雅,且无需关闭线程池,但它的缺点是只能使用一次,CountDownLatch创建之后不能被重复使用,也就是说 CountDownLatch 可以理解为只能使用一次的计数器。

四、拓展CountDownLatch类的API

1、构造方法

//参数count为计数值
public CountDownLatch(int count) {};
//1、调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };   
//2、和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//3、将count值减1
public void countDown() { };

五、线程池相关的API

ThreadPoolExecutor 中的 shutdown() 、shutdownNow() 、awaitTermination()的用法和区别

1、shutdown()

正常关闭,将线程池状态置为SHUTDOWN,线程池并不会立即停止

  1. 停止接收外部submit的任务
  2. 内部正在跑的任务和队列里等待的任务,会执行完
  3. 等到第二步完成后,才真正停止

1、shutdownNow
强行关闭,将线程池状态置为STOP。企图立即停止,事实上不一定:

  1. 跟shutdown()一样,先停止接收外部提交的任务
  2. 忽略队列里等待的任务
  3. 尝试将正在跑的任务interrupt中断
  4. 返回未执行的任务列表

shutdownNow()它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,调用interrupt()方法并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息,interrupt()只能响应可中断的阻塞,对于不可中断的阻塞,我们需要找到线程阻塞的原因并特殊处理。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。

3、awaitTermination()

作用: 当前线程阻塞,直到等所有已提交的任务执行完 ,这里包括正在跑的和队列中等待的,或者等超时时间到或者线程被中断,抛出InterruptedException,然后返回true,shutdown()可以和awaitTermination()方法一起使用

4、isShutDown

当调用shutdown()或shutdownNow()方法后返回为true。

5、isTerminated

1、当调用shutdown()方法后,并且所有提交的任务完成后返回为true;
2、当调用shutdownNow()方法后,成功停止后返回为true;
3、如果线程池任务正常完成,都为false