ThreadPoolExecutor/ExecutorService:线程池,使用线程池可以复用线程,降低频繁创建线程造成的性能消耗,同时对线程的创建、启动、停止、销毁等操作更简便。
CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。
例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
import java.util.concurrent.*;
public class CountDownTest {
public static void main(String[] args) {
int num = 100;
//启用线程池(最大不能超过500个)
ThreadPoolExecutor executor = new ThreadPoolExecutor(50,//核心池大小
500,//最大池大小
200,//线程最大空闲时间,超过此空闲时间可以被收回
TimeUnit.MILLISECONDS, //最大空闲时间的单位
new ArrayBlockingQueue<Runnable>(10)//用于保存执行任务的队列,可以选择其他不同的队列来做任务管理
);
CountDownLatch n = new CountDownLatch(num);
for (int i = 0; i < num; i++) {
//启动一个任务
Task myTask = new Task(i, n);
executor.execute(myTask);
}
System.out.println("全部执行的任务数量:" + executor.getTaskCount());
System.out.println("已完成的任务数量:" + executor.getCompletedTaskCount());
System.out.println("线程池中最大线程数量:" + executor.getPoolSize());
//等待所有线程完毕
try {
n.await();
} catch (InterruptedException e) {
System.out.println(e);
}
//关闭线程池
executor.shutdown();
}
}
class Task implements Runnable {
private int taskNum;
CountDownLatch n;
public Task(int num, CountDownLatch n) {
this.taskNum = num;
this.n = n;
}
public void run() {
try {
Thread.sleep(1000);
System.out.println("擦桌子");
} catch (Exception e) {
System.out.println("task " + taskNum + "执行失败");
}
//事情干完了
n.countDown();
}
}