CountDownLatch和Cyclibarrier 都是jdk并发包中提供的用于多个线程都达到某个点后再进行操作的工具类
CountDownLatch
countDownLatch 是一个倒计时器,它可以让某一个线程等待直到得到及时结束才开始执行。
- 构造函数可接收一个整数作为参数,表示计数器的计数个数
public CountDownLatch(int count)
- demo
public class CountDownLatchTest {
public static class Soldier implements Runnable {
CountDownLatch latch;
int i;
public Soldier(CountDownLatch latch, int i) {
this.latch = latch;
this.i = i;
}
@Override
public void run() {
try {
Thread.sleep(Math.abs(new Random().nextInt() % 10000));
System.out.println("士兵" + (i + 1) + "在任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
public static class General implements Runnable{
CountDownLatch latch;
public General (CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
latch.await(10, TimeUnit.SECONDS);
System.out.println("司令:任务完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(0, 10,
0L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),new ThreadPoolExecutor.CallerRunsPolicy());
int n = 10;
CountDownLatch latch = new CountDownLatch(n);
for (int i = 0; i < 10; i++) {
executor.submit(new Soldier(latch, i));
}
executor.submit(new General(latch));
}
}
输出结果
士兵1在任务完成
士兵7在任务完成
士兵4在任务完成
士兵2在任务完成
士兵8在任务完成
士兵6在任务完成
士兵10在任务完成
士兵3在任务完成
士兵9在任务完成
士兵5在任务完成
司令:任务完成
每一个士兵线程在线程执行完毕后调用了countDownLatch.countDown(),倒计时会减1,司令线程在执行到countDownLatch.await()时,如果countDownLatch不是0则等待到一直到倒计时为0后才继续执行!
CycliBarrier
CycliBarrier与countDownLatch有类似的功能且比CountDownLatch更强大。CycliBarrier好比如栅栏,当线程都执行到某一点后,将线程拦了下来,所有线程都达到后再继续下面操作。且CycliBarrir可以循环利用。
- 构造方法,第一个参数表示参与的线程总数,第二个参数表示后续操作
public CyclicBarrier(int parties, Runnable barrierAction)
- demo
public class CycliBarrierTest {
public static class Soldier implements Runnable {
private String soldier;
private final CyclicBarrier cyclic;
public Soldier(CyclicBarrier cyclic, String soldier) {
this.soldier = soldier;
this.cyclic = cyclic;
}
@Override
public void run() {
try {
cyclic.await();
doWork();
cyclic.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
void doWork() {
try {
Thread.sleep(Math.abs(new Random().nextInt() % 10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(soldier + ":任务完成");
}
}
public static class BarrierRun implements Runnable {
boolean flag;
int N;
public BarrierRun(boolean flag, int N) {
this.flag = flag;
this.N = N;
}
@Override
public void run() {
if (flag) {
System.out.println("司令:[士兵" + N + "个,任务完成!]");
} else {
System.out.println("司令:[士兵" + N + "个,集合完毕!]");
flag = true;
}
}
}
public static void main(String[] args) {
final int N = 10;
Thread[] allSoldier = new Thread[N];
boolean flag = false;
CyclicBarrier cyclic = new CyclicBarrier(N, new BarrierRun(flag, N));
//设置屏障点,主要为了执行这个方法
System.out.println("集合队伍! ");
for (int i = 0; i < N; i++) {
System.out.println("士兵" + i + "报道! ");
allSoldier[i] = new Thread(new Soldier(cyclic, "士兵" + i));
allSoldier[i].start();
}
}
}
执行结果
集合队伍!
士兵0报道!
士兵1报道!
士兵2报道!
士兵3报道!
士兵4报道!
士兵5报道!
士兵6报道!
士兵7报道!
士兵8报道!
士兵9报道!
司令:[士兵10个,集合完毕!]
士兵1:任务完成
士兵7:任务完成
士兵5:任务完成
士兵3:任务完成
士兵6:任务完成
士兵9:任务完成
士兵2:任务完成
士兵8:任务完成
士兵0:任务完成
士兵4:任务完成
司令:[士兵10个,任务完成!]
士兵线程的run方法中,在执行前调用了cycliBarrir的await(),等待所有线程都到达后,当所有线程都到达后,这一次的计数完成,当work()后再一次调用了await()方法,重新进行下一次计数
区别
CountDownLatch是在当所有线程都到达某一点后,等待的线程才可以继续进行。CycliBarrir 是在线程都到达某一点后,先到达的线程会等待到所有线程都到达后再继续进行!