1.使用isTerminated方法判断
当调用ExecutorService.shutdown方法的时候,线程池不再接收任何新任务,但此时线程池并不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
在调用shutdown方法后我们可以在一个死循环里面用isTerminated方法判断是否线程池中的所有线程已经执行完毕。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
8,
16,
30,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1024));
int taskCount=1000;
for (int i = 0; i < taskCount; i++) {
final int t=i;
threadPoolExecutor.submit(()->{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t);
});
}
threadPoolExecutor.shutdown();
while(true){
System.out.println("结束了吗?");
Thread.sleep(100);
if(threadPoolExecutor.isTerminated()){
System.out.println("都结束了!");
break;
}
}
}
}
2.使用CountDownLatch
判断线程池中的线程是否全部执行完毕的另外一种解决方案则是使用闭锁(CountDownLatch)来实现,CountDownLatch是一种灵活的闭锁实现,它可以使一个或多个线程等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,即表示需要等待的事情都已经发生。可以使用闭锁来这样设计程序达到目的:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
8,
16,
30,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1024));
int taskCount = 1000;
CountDownLatch cd = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
final int t = i;
threadPoolExecutor.submit(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t);
cd.countDown();
});
}
threadPoolExecutor.shutdown();
cd.await();
System.out.println("所有的子线程都结束了!");
}
}
3.使用awaitTermination方法
public boolean awaitTermination(long timeout, TimeUnit unit)
当使用awaitTermination时,主线程会处于一种等待的状态,等待线程池中所有的线程都运行完毕后才继续运行。
在以下任意一种情况发生时都会导致该方法的执行:
1)shutdown方法被调用之后
2)参数中定义的timeout时间到达或者当前线程被打断
这两情况任意一个发生了都会导致该方法在所有任务完成之后才执行。第一个参数是long类型的超时时间,第二个参数可以为该时间指定单位。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
8,
16,
30,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1024));
int taskCount = 1000;
for (int i = 0; i < taskCount; i++) {
final int t = i;
threadPoolExecutor.submit(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t);
});
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(30,TimeUnit.MINUTES);
System.out.println("所有的子线程都结束了!");
}
}
与shutdown()方法结合使用时,尤其要注意的是shutdown()方法必须要在awaitTermination()方法之前调用,该方法才会生效。否则会造成死锁。