javadoc里面的描述是这样的。
CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.(其它线程完成一些操作,但不等于这些线程要结束,也要不结束)
CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
可能是我的英语不够好吧, 我感觉从这个javadoc里面要准确理解他们的差异还是不容易的。
我的理解是
CountDownLatch: 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。
CyclicBarrier: N个线程相互等待,只要有任何一个线程没有完成,其它的N-1个线程都必须等待。
这样应该就清楚一点了,
对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。
而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。
CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.
而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.
在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的(因为整个流程已经完成了,不需要再来一次,所以一次性),而CyclicBarrier在调用reset之后还可以继续使用。那如果只是这么简单的话,我觉得CyclicBarrier简单命名为ResetableCountDownLatch好了,显然不是的。
上面是从设计目的去看这两个类。
http://blog.csdn.net/kjfcpua/article/details/7300286
用法:
一、CountDownLatch用法
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
CountDownLatch类只提供了一个构造器:
public CountDownLatch(int count) { }; //参数count为计数值
然后下面这3个方法是CountDownLatch类中最重要的方法:
public void await() throws InterruptedException { }; //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行 public void countDown() { }; //将count值减1
二、CyclicBarrier用法
通过它可以实现让一组线程等待至某个状态之后再全部同时执行,并且当所有等待线程都被释放以后,CyclicBarrier还可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。
CyclicBarrier类位于java.util.concurrent包下,CyclicBarrier提供2个构造器:
public CyclicBarrier(int parties, Runnable barrierAction) { } public CyclicBarrier(int parties) { }
参数parties指定让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。
然后CyclicBarrier中最重要的方法就是await方法,它有2个重载版本:
public int await() throws InterruptedException, BrokenBarrierException { }; public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };
第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。
http://www.cnblogs.com/codeOfLife/p/5687691.html
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; public class CyclicBarrierDemo { private static final Logger LOGGER = LoggerFactory.getLogger(CyclicBarrierDemo.class); public static void main(String[] args) throws InterruptedException { int parties = 4; int count = parties + 1; CountDownLatch startGate = new CountDownLatch(count); CyclicBarrier barrier = new CyclicBarrier(parties); for (int i = 0; i < parties; i++) { Thread thread = new Thread(new Writer(barrier, startGate), "demo" + i); thread.start(); } LOGGER.info(" "); int timeout = 6; LOGGER.info("主线程 还需要再阻塞{}s",timeout); new Thread(() -> { try { LOGGER.info("现在开始{}s等待。 CountDownLatch才允许主线程结束阻塞状态",timeout); TimeUnit.SECONDS.sleep(timeout); startGate.countDown(); LOGGER.info("{}s等待结束.主线程可以往下走了",timeout); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); startGate.await();//当前线程(main线程)被阻塞,直到startGate的countDown方法的次数和设定的值相同,其它的不要求 LOGGER.info("====不管Writer线程是否完成,只要countDown的调用次数够了,CountDownLatch就会解除主线程的阻塞状态===="); LOGGER.info(" "); TimeUnit.SECONDS.sleep(10); LOGGER.info(" "); LOGGER.info("======================CyclicBarrier的可重用性开始======================"); LOGGER.info(" "); int lessParties = parties - 1; for (int i = 0; i < lessParties; i++) { Thread thread = new Thread(new Writer(barrier, startGate), "damo" + (i + parties)); thread.start(); } startGate.await();//不会阻塞主线程运行,但write线程会执行不完 LOGGER.info("目前只调用{}次countDown,虽然小于设置的count {},但仍然不会阻塞主线程",lessParties,count); LOGGER.info("CyclicBarrier仍然需要{}个线程都至barrier状态,否则相关的Write线程都需要阻塞。目前只有{}个parties。" + "\n 因此所有的Writer线程会一起阻塞下去forever until server shutdown",parties,lessParties); } static class Writer implements Runnable { private CyclicBarrier cyclicBarrier; private CountDownLatch startGate; Writer(CyclicBarrier cyclicBarrier, CountDownLatch startGate) { this.cyclicBarrier = cyclicBarrier; this.startGate = startGate; } @Override public void run() { try { startGate.countDown(); LOGGER.info("线程" + Thread.currentThread().getName() + "cyclicBarrier.await()前执行,等待其他线程写入完毕"); cyclicBarrier.await(); TimeUnit.SECONDS.sleep(10);//sleep一会。这样日志中可以很好的看到cyclicBarrier.await()的可重用性r } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } LOGGER.info(Thread.currentThread().getName() + "cyclicBarrier.await()后执行......"); } } }
Output:
22:15:31.632 [demo0] INFO CyclicBarrierDemo - 线程demo0cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:31.632 [demo3] INFO CyclicBarrierDemo - 线程demo3cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:31.632 [demo2] INFO CyclicBarrierDemo - 线程demo2cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:31.632 [demo1] INFO CyclicBarrierDemo - 线程demo1cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:31.632 [main] INFO CyclicBarrierDemo - 22:15:31.637 [main] INFO CyclicBarrierDemo - 主线程 还需要再阻塞6s 22:15:31.763 [Thread-0] INFO CyclicBarrierDemo - 现在开始6s等待。 CountDownLatch才允许主线程结束阻塞状态 22:15:37.765 [main] INFO CyclicBarrierDemo - ====不管Writer线程是否完成,只要countDown的调用次数够了,CountDownLatch就会解除主线程的阻塞状态==== 22:15:37.765 [main] INFO CyclicBarrierDemo - 22:15:37.765 [Thread-0] INFO CyclicBarrierDemo - 6s等待结束.主线程可以往下走了 22:15:41.638 [demo3] INFO CyclicBarrierDemo - demo3cyclicBarrier.await()后执行...... 22:15:41.638 [demo2] INFO CyclicBarrierDemo - demo2cyclicBarrier.await()后执行...... 22:15:41.638 [demo0] INFO CyclicBarrierDemo - demo0cyclicBarrier.await()后执行...... 22:15:41.638 [demo1] INFO CyclicBarrierDemo - demo1cyclicBarrier.await()后执行...... 22:15:47.765 [main] INFO CyclicBarrierDemo - 22:15:47.765 [main] INFO CyclicBarrierDemo - CyclicBarrier的可重用性开始: 22:15:47.765 [main] INFO CyclicBarrierDemo - 22:15:47.765 [main] INFO CyclicBarrierDemo - 目前只调用3次countDown,虽然小于设置的count 5,但仍然不会阻塞主线程 22:15:47.765 [main] INFO CyclicBarrierDemo - 但CyclicBarrier仍然需要4个线程都至barrier状态。目前只有3个parties。 因此所有的Writer线程会一起阻塞下去forever until server shutdown 22:15:47.765 [damo4] INFO CyclicBarrierDemo - 线程damo4cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:47.766 [damo5] INFO CyclicBarrierDemo - 线程damo5cyclicBarrier.await()前执行,等待其他线程写入完毕 22:15:47.766 [damo6] INFO CyclicBarrierDemo - 线程damo6cyclicBarrier.await()前执行,等待其他线程写入完毕