在上一篇博客中,我们用Callable实现了这个功能:用Callable实现在走完10个线程之后再进行操作,其中也提到了使用CountDownLatch实现是一个更好地选择,下面,我们就来看看如何使用用CountDownLatch实现在走完10个线程之后再进行操作。 我们先来看看《JAVA编程思想第四版》中对CountDownLatch的描述:
CountDownLatch被用来同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。
你可以向CcountDownLatch对象设置一个初始计数值,任何在这个对象上调用wait的方法都将阻塞,直至这个计数值到达0。
其他任务在结束其工作时,可以再该对象上调用countDown()来减小这个计数值。CountDownLatch被设计为只触发一次,计数值
不能被重置。如果你需要能够重置计数值的版本,则可以使用CyclicBarrier。
调用countDown()的任务在产生这个调用时并没有被阻塞只有对await()的调用会被阻塞,直到计数值到达0.
CountDownLatch的典型用法是将一个程序分为n个互相独立的可解决的任务,并创建值为0的CountDownLatch。(此处
应该是创建值为n的CountDownLatch)当每个任务完成时,都会在这个锁存器上调用countDown()。等待问题呗解决的
任务在这个锁存器上调用await(),将他们自己拦住,直到锁存器上技术结束。
再来看看具体要求的具体应用:
/**
* 2018-05-05
* @author liujie
*
*/
public class TestCountDownLatch {
public static void main(String[] args) throws Exception{
int SIZE = 10;
CountDownLatch latch = new CountDownLatch(SIZE);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
List<Runnable> threads = new ArrayList<Runnable>();
for (int i = 0; i < SIZE; i++) {
//多个任务线程共享一个CountDownLatch实例
threads.add(new MyThread(latch));
}
for (Runnable runnable : threads) {
Thread.sleep(50);
cachedThreadPool.execute(runnable);
}
System.out.println("main Thread finished starting threads--"
+ new Date().getSeconds());
//主线程会在这里等待,直到latch计数值到达0
latch.await();
//当latch计数值到达0,说明任务线程都完成了各自任务,主线程继续往下
System.out.println("main Thread go on working--" + new Date().getSeconds());
}
}
class MyThread implements Runnable{
private CountDownLatch latch;
private static transient int count = 0;
private static Random random = new Random();
private int id = count ++;
public MyThread(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
int workTimeSeconds = random.nextInt(10) + 1;
System.out.println("Thread-" + id + "\tstart running for "
+ workTimeSeconds + " seconds--" + new Date().getSeconds());
try {
Thread.sleep(1000 * workTimeSeconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在完成自己的任务后,将latch的计数值减一
latch.countDown();
}
}
以下是控制台的打印:
Thread-2 start running for 8 seconds--41
Thread-1 start running for 2 seconds--41
Thread-3 start running for 3 seconds--41
Thread-0 start running for 5 seconds--41
Thread-4 start running for 2 seconds--41
Thread-5 start running for 6 seconds--41
Thread-6 start running for 4 seconds--42
Thread-7 start running for 9 seconds--42
Thread-8 start running for 4 seconds--42
main Thread finished starting threads--42
Thread-9 start running for 1 seconds--42
main Thread go on working--51
由运行结果可知,程序实现了完成了题目的要求,主线程在第51秒的时候继续下面的任务,这是因为任务线程7是最后一个完成的任务(第42秒开始,耗时9秒,在51秒时完成).
我对CountDownLatch的理解:
就相当于一个组长,在接到一个任务以后,将任务分为N份,并在一个任务计数器开启N个亮灯进行记录(new CountDownLath(N)),然后将这N份任务交给N个组员去完成(threadPool开启N个线程)。每个组员在接到任务后就各自忙自己的,在完成了他们的任务以后,就在任务计数器上熄灭一个灯(latch.countDown()),提示已经完成了自己的任务。有需要的人就会对这个任务计数器进行监控(latch.await()),直到所有的等都熄灭了,才会继续工作。