并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier
Java并发编程实践 目录
并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier
并发编程 06—— CompletionService : Executor 和 BlockingQueue
并发编程 10—— 任务取消 之 关闭 ExecutorService
并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略
概述
第1部分 闭锁
闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。当闭锁到达结束状态后,将不会再改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其他活动都完成后才继续执行。例如:
- 确保某个计算在其需要的所有资源都被初始化之后才继续执行。
- 确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
- 等待直到某个操作的所有参与者都就绪再继续执行。
CountDownLatch是一种灵活的闭锁实现,可以再上述各种情况中使用,它可以使一个或多个线程等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到0,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么await会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时。
下面程序TestHarness中给出了闭锁的两种常见用法。TestHarness创建一定数量的线程,利用它们并发地执行指定的任务。它使用两个闭锁,分别表示“起始门”和“结束门”。起始门计数器的初始值为1,而结束门计数器的初始值为工作线程的数量。每个工作线程首先要做到就是在启动门上等待,从而确保所有线程都就绪后才开始执行。而每个线程要做的最后一个事情是将调用结束门的countDown方法减1 ,这能使主线程高效低等待直到所有工作线程都执行完毕,因此可以统计所消耗的时间。
package com.concurrency.BasicBuildingBlocks_5; import java.util.concurrent.CountDownLatch; /**
* 5.11 在计时测试中使用CountDownLatch来启动和停止线程(闭锁)
*
* @ClassName: TestHarness
* TODO
* @author Xingle
* @date 2014-9-4 下午2:56:29
*/
public class TestHarness { int nThreads ;
Runnable task;
public TestHarness(int nThreads,Runnable task){
this.nThreads = nThreads;
this.task = task;
}
public long timeTask(){ //起始门
final CountDownLatch startGate = new CountDownLatch(1);
//结束门
final CountDownLatch endGate = new CountDownLatch(nThreads);
for(int i = 0;i<nThreads;i++){
Thread thread = new Thread(){
public void run(){
//每个线程在启动门上等待,确保所有线程都就绪后才开始
try {
startGate.await();//等待计数器达到0
try{
task.run();
}finally{
//每个线程结束后,调用countDown递减计数器,表示一个事件发生
endGate.countDown();
}
} catch (InterruptedException e) {
e.printStackTrace();
} }
};
thread.start();
}
long start = System.nanoTime();
//启动门发生
startGate.countDown();
try {
//等待结束门的线程都结束
endGate.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.nanoTime();
return end - start;
}
}
测试程序:
package com.concurrency.BasicBuildingBlocks_5; /**
*
* @ClassName: TestHarnessMain
* TODO
* @author Xingle
* @date 2014-9-4 下午3:27:18
*/
public class TestHarnessMain { public static void main(String[] args){
Runnable task = new Runnable() { @Override
public void run() {
System.out.println("执行任务,我是线程:"+Thread.currentThread().getName());
}
};
int count = 10;
TestHarness testHarness = new TestHarness(count, task );
long time = testHarness.timeTask();
System.out.println("闭锁 测试结果 执行"+count+"个线程"+" 一共用时:"+time);
}
}
执行结果:

第2部分 栅栏
上面已经看到通过闭锁来启动一组相关的操作,或者等待一组相关的操作结束。闭锁是一次性对象,一旦进入终止状态,就不能被重置。
栅栏(Barrier)类似于闭锁,它能阻塞一组线程直到某个事件发生。栅栏与闭锁的关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。(栅栏则是所有线程相互等待,直到所有线程都到达某一点时才打开栅栏,然后线程可以继续执行。)
CyclicBarrier 可以使一定数量的参与方反复地在栅栏位置汇集,它在并行迭代算法中非常有用。CyclicBarrier支持一个可选的 Runnable 参数,当线程通过栅栏时,runnable对象将被调用。构造函数CyclicBarrier(int parties, Runnable barrierAction),当线程在CyclicBarrier对象上调用await()方法时,栅栏的计数器将增加1,当计数器为parties时,栅栏将打开。
package com.concurrency.BasicBuildingBlocks_5; import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; /**
*
* @ClassName: Worker
* @author Xingle
* @date 2014-9-9 上午10:41:17
*/
public class Worker implements Runnable { final int id;
final CyclicBarrier barrier; public Worker(int id, CyclicBarrier barrier) {
this.id = id;
this.barrier = barrier;
} @Override
public void run() {
System.out.println(this.id + " start to run!");
try {
this.barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} } }
测试程序:
package com.concurrency.BasicBuildingBlocks_5; import java.util.concurrent.CyclicBarrier; /**
*
* @ClassName: Beer
* 有五个人参与跑步,规定五个人只要都跑到终点了,大家可以喝啤酒。但是,只要有一个人没到终点,就不能喝。 这里没有要求大家要同时起跑
* @author Xingle
* @date 2014-9-9 上午10:40:36
*/
public class Beer {
public static void main(String[] args){
final int count = 5;
final CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() { @Override
public void run() {
System.out.println("drink beer!");
}
}); for (int i =0; i<count;i++){
new Thread(new Worker(i, barrier)).start();
}
} }
执行结果:

参考:
1.《并发编程实战》 5.5 同步工具类
2.尽量把CyclicBarrier和CountDownLatch的区别说通俗点
并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier的更多相关文章
- 闭锁CountDownLatch与栅栏CyclicBarrier
https://blog.csdn.net/lmc_wy/article/details/7866863 闭锁CountDownLatch与栅栏CyclicBarrier 浅谈 java ...
- Java并发编程之闭锁CountDownLatch简单介绍
闭锁相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭着的,没有不论什么线程能够通过,当到达结束状态时.这扇门才会打开并容许全部线程通过.它能够使一个或多个线程等待一组事件发生. 闭锁状态包含一个 ...
- 并发编程-concurrent指南-回环栅栏CyclicBarrier
字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行. java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步 ...
- Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo
Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...
- Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...
- Java并发编程之闭锁与栅栏
一.前言 闭锁与栅栏是在多线程编程中的概念,因为在多线程中,我们不能控制线程的执行状态,所以给线程加锁,让其按照我们的想法有秩序的执行. 闭锁 CountDownLatch,实例化时需要传入一个int ...
- java并发编程JUC第十篇:CyclicBarrier线程同步
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
- Java 并发编程中的 CountDownLatch 锁用于多个线程同时开始运行或主线程等待子线程结束
Java 5 开始引入的 Concurrent 并发软件包里面的 CountDownLatch 其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是 ...
- JUC 并发编程--04 常用的辅助类CountDownLatch , CyclicBarrier , Semaphore , 读写锁 , 阻塞队列,CompletableFuture(异步回调)
CountDownLatch 相当于一个减法计数器, 构造方法指定一个数字,比如6, 一个线程执行一次,这个数字减1, 当变为0 的时候, await()方法,才开始往下执行,, 看这个例子 Cycl ...
随机推荐
- tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。
简要教程 tween.js是一款可生成平滑动画效果的js动画库.相关的动画库插件还有:snabbt.js 强大的jQuery动画库插件和Tweene-超级强大的jQuery动画代理插件. tween. ...
- Velocity(5)——#set指令
引用可以让模板设计者生成动态内容,而指令允许设计者真正的负责页面的展现和内容. 指令是以#开头,后面紧跟一个关键字,比如if,else,foreach等.而这个关键字,是可以被放在{}中间的.这是规范 ...
- 【转】赞一下huicpc035
以下转自:http://hi.baidu.com/fpkelejggfbfimd/item/99421eaefa93a814a9cfb722 本来以为HNU的huicpc035和我一样退役了,后来听说 ...
- AJAX-----07XMLHttpRequest对象的处理返回的JSON类型数据
要玩json首先就需要知道一般都数据是怎么处理的: <!DOCTYPE html> <html lang="en"> <head> <me ...
- 设置IE默认文本模式的方法
设置IE默认文本模式的方法 <meta http-equiv="X-UA-Compatible" content="IE=8" /> IE=5.6. ...
- Url中處理空格、特殊字符
publicvoid UrlEncodeTest(){ string url ="C++ C#"; Console.WriteLine(HttpUtility.UrlE ...
- Windows消息机制概述
消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用程 ...
- 关于ScrollView和listview的冲突关于的滑动和宽度
listview和ScrollView嵌套有两个冲突,关于listview显示不全的问题和listview和scrollview的滑动冲突 自定义listview package com.exmple ...
- wex5 教程 之 图文讲解 可观察对象的集群应用与绑定技术
一 前言: wex5官方教程里,开篇即以一个input输入,output即时输出的例子,为我们展现了一个概念:可观察对象.在以后我的项目开发中,将大量运用可观察对象. 那么,问题来了: 1. 可观察对 ...
- IsBackground的理解
1.当在主线程中创建了一个线程,那么该线程的IsBackground默认是设置为FALSE的. 2.当主线程退出的时候,IsBackground=FALSE的线程还会继续执行下去,直到线程执行结束. ...