最近遇到一个问题,需要批量的从数据库中读取数据,但是对于数据的处理需要等待一部分完成之后再进行下一批的数据。抽象出来就是一个任务,分成N份来执行,每一份由多个线程去执行,一份完成之后再执行下一份。于是想起了CountDownLatch。
网上关于CountDownLatch的文章很多,搜了一些,也大体看了一下,但是感觉最好的还是CountDownLatch官方代码里面的两个例子,现在把这两个例子简单说明一下。
CountDownLatch一个线程同步的工具,是的一个或者多个线程等待其他线程操作完成之后再执行。
CountDownLatch通过一个给定的数值count来进行初始化,方法await()一直阻塞直到当前的count到达零为止,count的数值通过countDown()方法来减1,count的数值一旦设定就不能再修改,如果需要进行修改,请考虑使用CyclicBarrier。
大体看了一下源代码,是通过同步队列来作为计数器来进行控制的。同步队列是在CountDownLatch内部实现了一个静态内部类,countDown()通过调用队列来减1。
有两个典型的应用场景:
第一种是一个开始的信号,所有的task任务等待这个信号。类似于百米赛跑中的信号员,所有的运动员都做好准备,等待信号,信号一来,那就开始运行。
第二种是将一个任务分支N部分由M个线程来处理,等待所有的线程M完成任务后做其他的事情,还是刚才的例子,所有运动员跑完之后,才能知道所有人员的排名情况。
public class CountDownLatchTest { public static void main(String[] args) throws Exception{ CountDownLatch s = new CountDownLatch(1); CountDownLatch e = new CountDownLatch(6); for(int i=0;i<6;i++){ new Thread(new Worker(s,e)).start(); } System.out.println("i am the judge ,now ,i start the singal"); s.countDown(); System.out.println("waiting all task over"+e.getCount()); e.await(); System.out.println("all is over"); } } class Worker implements Runnable{ private final CountDownLatch startSingal ; private final CountDownLatch endSingal; public Worker(CountDownLatch startSingal, CountDownLatch endSingal) { super(); this.startSingal = startSingal; this.endSingal = endSingal; } public void run() { try { System.out.println(Thread.currentThread().getName()+"waiting the start singal...."+startSingal.getCount()); //等待开始信号信号 startSingal.await(); System.out.println(Thread.currentThread().getName()+"start to executer"); //结束的计数器减一 endSingal.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
扫描二维码关注公众号,回复:
699363 查看本文章
执行结果:
Thread-0waiting the start singal....1
Thread-2waiting the start singal....1
Thread-1waiting the start singal....1
i am the judge ,now ,i start the singal
waiting all task over6
Thread-1start to executer
Thread-3waiting the start singal....1
Thread-4waiting the start singal....1
Thread-3start to executer
Thread-5waiting the start singal....0
Thread-5start to executer
Thread-2start to executer
Thread-0start to executer
Thread-4start to executer
all is over
public static void main(String[] args) throws Exception{ CountDownLatch latch = new CountDownLatch(6); Executor e = Executors.newFixedThreadPool(6); System.out.println("thread number is 6,now start"); for(int i=0;i<6;i++){ e.execute(new Worker(latch,i)); } System.out.println("waiting all is over "); latch.await(); System.out.println("all is over"); } } class Worker implements Runnable{ private final CountDownLatch number; private int temp; public Worker(CountDownLatch number, int temp) { super(); this.number = number; this.temp = temp; } public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName()+"runnable - "+temp); number.countDown(); } }
写道
thread number is 6,now start
waiting all is over
pool-1-thread-4runnable - 3
pool-1-thread-5runnable - 4
pool-1-thread-1runnable - 0
pool-1-thread-3runnable - 2
pool-1-thread-2runnable - 1
pool-1-thread-6runnable - 5
all is over
waiting all is over
pool-1-thread-4runnable - 3
pool-1-thread-5runnable - 4
pool-1-thread-1runnable - 0
pool-1-thread-3runnable - 2
pool-1-thread-2runnable - 1
pool-1-thread-6runnable - 5
all is over