开发中常常遇到需要用线程池来解决多任务并发的问题,在使用JUC下的线程池执行并发任务之后,往往很难判断任务是不是都执行完成,但是这种判断又是非常必要的。下面就介绍三种常用的判断所有任务是否执行完毕的方法。
1,利用线程池自身的 isTerminated()方法。
boolean isTerminated()
如果关闭后所有任务都已完成,则返回 true。注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
public class EsPoolShutDownDemo {
public static void main(String[] args){
//开启线程池,corePoolSize为10 。
ExecutorService esPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10000000; i++) {
final int num = i;
Runnable task = new Runnable() {
public void run() {
try {
//线程执行任务
System.out.println(num);
} catch (Exception e) {
e.printStackTrace();
}
}
};
esPool.submit(task);
}
//停止线程池
esPool.shutdown();
while(true) {
//只有当线程池中所有线程完成任务时才会返回true,并且需要先调用线程池的shutdown方法或者shutdownNow方法。
if(esPool.isTerminated()) {
System.out.println("All finished");
}
}
}
}
2,使用CountDownLatch
CountDownLatch能够使一个或多个线程等待其他线程完成各自的工作后再执行;
public class CountDownLatchDemo {
public static void main(String[] args) {
//定义总共需要执行的任务数
final int nThreads = 10;
final CountDownLatch endGate = new CountDownLatch(nThreads);
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < nThreads; i++) {
final int num = i;
Runnable task = new Runnable() {
public void run() {
try {
//执行任务
System.out.println(num);
} catch (Exception e) {
e.printStackTrace();
} finally {
//计数器减少数量
endGate.countDown();
}
}
};
exec.submit(task);
}
try {
//等待计数器数字减到0,即等待到所有任务完成。当减到0之后才会继续执行后面的代码
endGate.await();
System.out.println("All finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3,使用Semaphore
Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或逻辑的)线程数目。
public class SemaphoreDemo {
public static void main(String[] args){
final Semaphore semaphore = new Semaphore(10);
//开启线程池,corePoolSize为10 。
ExecutorService exec = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10000000; i++) {
final int num = i;
Runnable task = new Runnable() {
public void run() {
try {
//获取锁
semaphore.acquire();
//线程执行任务
System.out.println(num);
//释放锁
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
}
};
exec.submit(task);
}
//停止线程池
exec.shutdown();
try {
//当线程池中线程执行完任务之前一直阻塞
//或者任务没执行完,但是到了1小时的过期时间之后,也会解除阻塞
exec.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上面3个方法中,第一个最普遍,后两个使用少一些。性能方面,第一种和第三种较好,推荐使用。