http://xijunhu.iteye.com/blog/713433
http://www.blogjava.net/jlins-you/archive/2012/04/24/376516.html
徐明明:http://xumingming.sinaapp.com/215/countdownlatch-vs-cyclicbarrier/
CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。
CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。
CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.
CyclicBarrier像是一个(主线程)裁判,其他子线程是绕圈跑的运动员。每一轮都得等到所有运动员都跑到了终点(也是起点),裁判宣读下本轮的结果,然后再发令,运动员开始下一轮的绕圈跑。当然,裁判也可以没有任何动作,等所有运动员都到终点后,就直接发令开跑。
class Worker implements Runnable { CyclicBarrier barrier; int id; int epoch; public Worker(CyclicBarrier barrier, int id, int epoch) { this.barrier = barrier; this.id = id; this.epoch = epoch; } @Override public void run() { for (int i = 0; i < epoch; ++i) { System.out.println("epoch:"+i+ " worker " + id + " start"); try { barrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("epoch:"+i+ " worker " + id + " end"); try { TimeUnit.MICROSECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception{ int n = 3; CyclicBarrier barrier = new CyclicBarrier(n, new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(3); System.out.println("Master: all workers had come, now go!"); } catch (InterruptedException e) { e.printStackTrace(); } } }); for (int i = 0; i < n; ++i) new Thread(new Worker(barrier, i, 3)).start(); }
epoch:0 worker 1 start
epoch:0 worker 0 start
epoch:0 worker 2 start
Master: all workers had come, now go!
epoch:0 worker 1 end
epoch:0 worker 2 end
epoch:0 worker 0 end
epoch:1 worker 1 start
epoch:1 worker 0 start
epoch:1 worker 2 start
Master: all workers had come, now go!
epoch:1 worker 1 end
epoch:1 worker 2 end
epoch:1 worker 0 end
epoch:2 worker 0 start
epoch:2 worker 1 start
epoch:2 worker 2 start
Master: all workers had come, now go!
epoch:2 worker 0 end
epoch:2 worker 2 end
epoch:2 worker 1 end
http://blog.csdn.net/yanhandle/article/details/9016329
CountDownLatch举例
CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行。 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下:
public boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
很简单,如果取得当前的状态为0,说明这个锁已经结束,直接返回false;如果没有结束,然后去设置计数器减1,如果compareAndSetState不成功,则继续循环执行。 而其中的一直等待计数器归零的方法是await()。
通过CountDownLatch可以做几件事情:
1. 主线程控制同时启动一组线程
final CountDownLatch count = new CountDownLatch(1);
for (int i = 0; i < 3; i++) {
new Thread("Thread" + i) {
public void run() {
System.out.println(Thread.currentThread().getName() + " wait");
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " start");
}
}.start();
}
//等等三秒,否则有可能3个线程并没有全部进行await状态
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.countDown();
2. 主线程等待各子线程全部执行完毕后再往下执行:
final CountDownLatch count = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread("Thread" + i) {
public void run() {
System.out.println(Thread.currentThread().getName() + " start");
count.countDown();
}
}.start();
}
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All end!!!");
import java.util.Random; import java.util.concurrent.CyclicBarrier; /** *//** * CyclicBarrier类似于CountDownLatch也是个计数器, * 不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数, * 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 * CyclicBarrier就象它名字的意思一样,可看成是个障碍, * 所有的线程必须到齐后才能一起通过这个障碍。 * CyclicBarrier初始时还可带一个Runnable的参数, * 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。 */ public class CyclicBarrierTest { public static class ComponentThread implements Runnable { CyclicBarrier barrier;// 计数器 int ID; // 组件标识 int[] array; // 数据数组 // 构造方法 public ComponentThread(CyclicBarrier barrier, int[] array, int ID) { this.barrier = barrier; this.ID = ID; this.array = array; } public void run() { try { array[ID] = new Random().nextInt(100); System.out.println("Component " + ID + " generates: " + array[ID]); // 在这里等待Barrier处 System.out.println("Component " + ID + " sleep"); barrier.await(); System.out.println("Component " + ID + " awaked"); // 计算数据数组中的当前值和后续值 int result = array[ID] + array[ID + 1]; System.out.println("Component " + ID + " result: " + result); } catch (Exception ex) { } } } /** *//** * 测试CyclicBarrier的用法 */ public static void testCyclicBarrier() { final int[] array = new int[3]; CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() { // 在所有线程都到达Barrier时执行 public void run() { System.out.println("testCyclicBarrier run"); array[2] = array[0] + array[1]; } }); // 启动线程 new Thread(new ComponentThread(barrier, array, 0)).start(); new Thread(new ComponentThread(barrier, array, 1)).start(); } public static void main(String[] args) { CyclicBarrierTest.testCyclicBarrier(); } }
首先在cyclicBarrier中设置线程数目n,
各个线程执行到barrier.await进入等待状态,
当各个线程调用cyclicBarrier中await的方法的次数达到n次时,
开始执行cyclicBarrier中定义的线程方法,待执行结束之后,等待的n个线程再次被唤醒,继续执行await之后的语句。
也就是说对于cyclicbarrier而言,不知道执行各个线程是啥,只知道一旦自己的await被调用了n次,自己内部的线程就开始执行,执行完之后,被堵塞的n个线程才继续执行
CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。
若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
示例用法:下面是一个在并行分解设计中使用 barrier 的例子:
在这个例子中,每个 worker 线程处理矩阵的一行,在处理完所有的行之前,该线程将一直在屏障处等待。
处理完所有的行之后,将执行所提供的 Runnable 屏障操作,并合并这些行。
如果合并者确定已经找到了一个解决方案,那么 done() 将返回 true,所有的 worker 线程都将终止。
如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。
为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:
if (barrier.await() == 0) {
// log the completion of this iteration
}对于失败的同步尝试,CyclicBarrier 使用了一种要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。
内存一致性效果:线程中调用 await() 之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 紧跟在从另一个线程中对应 await() 成功返回的操作。
(1)await
public int await() throws InterruptedException, BrokenBarrierException在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
最后一个线程到达;或者
其他某个线程中断当前线程;或者
其他某个线程中断另一个等待线程;或者
其他某个线程在等待 barrier 时超时;或者
其他某个线程在此 barrier 上调用 reset()。
如果当前线程:
在进入此方法时已经设置了该线程的中断状态;或者
在等待时被中断
则抛出 InterruptedException,并且清除当前线程的已中断状态。
如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。
如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。
如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
返回:
到达的当前线程的索引,其中,索引 getParties() - 1 指示将到达的第一个线程,零指示最后一个到达的线程
抛出:
InterruptedException - 如果当前线程在等待时被中断
BrokenBarrierException - 如果另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者在调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。
(2)getNumberWaiting
public int getNumberWaiting()返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言。
返回:
当前阻塞在 await() 中的参与者数目。
应用实例:
运行结果:
pool-1-thread-3已到达集合点1,现在共有1个线程到达,正在等待
pool-1-thread-2已到达集合点1,现在共有2个线程到达,正在等待
pool-1-thread-1已到达集合点1,现在共有3个线程到达,全部到齐,出发去下一个目标
pool-1-thread-3已到达集合点2,现在共有1个线程到达,正在等待
pool-1-thread-1已到达集合点2,现在共有2个线程到达,正在等待
pool-1-thread-2已到达集合点2,现在共有3个线程到达,全部到齐,出发去下一个目标
pool-1-thread-1已到达集合点3,现在共有1个线程到达,正在等待
pool-1-thread-2已到达集合点3,现在共有2个线程到达,正在等待
pool-1-thread-3已到达集合点3,现在共有3个线程到达,全部到齐,出发去下一个目标
pool-1-thread-1已到达集合点4,现在共有1个线程到达,正在等待
pool-1-thread-2已到达集合点4,现在共有2个线程到达,正在等待
pool-1-thread-3已到达集合点4,现在共有3个线程到达,全部到齐,出发去下一个目标
pool-1-thread-2已到达集合点5,现在共有1个线程到达,正在等待
pool-1-thread-3已到达集合点5,现在共有2个线程到达,正在等待
pool-1-thread-1已到达集合点5,现在共有3个线程到达,全部到齐,出发去下一个目标