CountDownLatch与CyclicBarrier的对比
CountDownLatch:
CountDownLatch通过计数器来实现,计数器表示线程的数量。每当一个线程执行结束后,计数器的值就会减1,并在await方法处阻塞。一旦计数器为0,所有阻塞的线程均被释放,await方法后所有后续动作都会开始执行。计数器无法被重置。
并发模拟CountDownLatch
1 import java.util.concurrent.CountDownLatch; 2 3 public class CountRunnable implements Runnable { 4 private CountDownLatch countDownLatch; 5 6 public CountRunnable(CountDownLatch countDownLatch) { 7 this.countDownLatch = countDownLatch; 8 } 9 10 @Override 11 public void run() { 12 try { 13 synchronized (countDownLatch) { 14 countDownLatch.countDown(); 15 System.out.println("down latch count = " + countDownLatch.getCount()); 16 } 17 countDownLatch.await(); 18 System.out.println("current count = " + (5 - countDownLatch.getCount())); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 } 23 }
1 import java.util.concurrent.CountDownLatch; 2 import java.util.concurrent.ExecutorService; 3 import java.util.concurrent.Executors; 4 5 public class CountDownTest { 6 public static void main(String[] args) { 7 ExecutorService pool = Executors.newCachedThreadPool(); 8 CountDownLatch cdl = new CountDownLatch(5); 9 for (int i = 0; i < 5; i++) { 10 CountRunnable countRunnable = new CountRunnable(cdl); 11 pool.execute(countRunnable); 12 } 13 } 14 }
控制台输出:
down latch count = 4 down latch count = 3 down latch count = 2 down latch count = 1 down latch count = 0 current count = 5 current count = 5 current count = 5 current count = 5 current count = 5
观察到线程countDownLatch.countDown()方法后阻塞在await方法处,当所有线程都执行countDownLatch.countDown()方法后,即计数器count减为0后,每个线程的await()方法就会立刻return,从而执行之后的方法
CyclicBarrier:
CyclicBarrier可以协同多个线程,每个线程到达这个屏障处时都会等待,直到所有线程都到达了这个屏障时,再一起继续执行后面的动作。
模拟CyclicBarrier
1 import java.util.concurrent.CyclicBarrier; 2 3 public class CyclicBarrierThread extends Thread { 4 private CyclicBarrier cb; 5 6 private int sleepSecond; 7 8 public CyclicBarrierThread(CyclicBarrier cb, int sleepSecond) { 9 this.cb = cb; 10 this.sleepSecond = sleepSecond; 11 } 12 13 public CyclicBarrier getCb() { 14 return cb; 15 } 16 17 public void setCb(CyclicBarrier cb) { 18 this.cb = cb; 19 } 20 21 public int getSleepSecond() { 22 return sleepSecond; 23 } 24 25 public void setSleepSecond(int sleepSecond) { 26 this.sleepSecond = sleepSecond; 27 } 28 29 public void run() { 30 try { 31 System.out.println(this.getName() + "start run ..."); 32 Thread.sleep(sleepSecond * 1000); 33 System.out.println(this.getName() + "start to wait, time is " + System.currentTimeMillis()); 34 cb.await(); 35 System.out.println(this.getName() + "end wait, time is " + System.currentTimeMillis()); 36 } catch (Exception e) { 37 e.printStackTrace(); 38 } 39 } 40 }
1 import java.util.concurrent.CyclicBarrier; 2 3 public class Test { 4 public static void main(String[] args) throws Exception { 5 Runnable runnable = new Runnable() { 6 @Override 7 public void run() { 8 System.out.println("CyclicBarrier的所有线程await()结束了,开始指定的Runnable运行, 时间为" + System.currentTimeMillis()); 9 } 10 }; 11 12 CyclicBarrier cb = new CyclicBarrier(3, runnable); 13 CyclicBarrierThread cbt0 = new CyclicBarrierThread(cb, 3); 14 CyclicBarrierThread cbt1 = new CyclicBarrierThread(cb, 6); 15 CyclicBarrierThread cbt2 = new CyclicBarrierThread(cb, 9); 16 cbt0.start(); 17 cbt1.start(); 18 cbt2.start(); 19 } 20 }
控制台输出
Thread-1 start run ... Thread-2 start run ... Thread-0 start run ... Thread-0 start to wait, time is 1575901627885 Thread-1 start to wait, time is 1575901630884 Thread-2 start to wait, time is 1575901633886 CyclicBarrier的所有线程await()结束了,开始指定的Runnable运行, 时间为1575901633886 Thread-2 end wait, time is 1575901633886 Thread-0 end wait, time is 1575901633886 Thread-1 end wait, time is 1575901633886
观察到所有线程都运行到了await()方法的时候,所有线程后面的代码以及指定的Runnable同时运行
综上:
1.CountDownLatch本质是一个计数器,线程执行一次,计数器减一,只能单次使用;而CyclicBarrier类似阀门或者栅栏,需要所有线程都到达,然后才能继续执行,可以多次使用
2.CountDownLatch当调用countDown()方法后的计数器等于指定的线程数之后,可以唤起多个线程的任务;而CyclicBarrier当执行到await()方法的线程数量等于指定的parties数量之后,只能唤起一个BarrierAction