并发编程 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 ...
随机推荐
- [Android Tips] 16. Update Android SDK from command-line
$ cd $ANROID_HOME $ tools/android update sdk -u -s 参数 -s --no-https : Uses HTTP instead of HTTPS (th ...
- IOS开始对App Store大扫除:你的APP更新了吗?
成都亿合科技小编从北京商报了解到,对于开发APP应用的要注意啦,IOS要开始对App Store大扫除:你的APP更新了吗? 日前苹果App Store的开发者们发送邮件,表示将实施一个持续评估应用行 ...
- Count Primes ----质数判断
质数的判断 埃拉托斯特尼筛法: 算法的过程如下图所示: 我们从2开始遍历到根号n,先找到第一个质数2,然后将其所有的倍数全部标记出来,然后到下一个质数3,标记其所有倍数,依次类推,直到根号n,此时数组 ...
- git设置hooks 钩子
github是可以设置hooks的,看:在设置webhooks & services,可在Just the push event.是设定向你的服务器发请求,然后再做相应的处理. https:/ ...
- SecureCRT使用小技巧
SecureCRT使用小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 欢迎加入:高级运维工程师之路 598432640 以前觉得xshell链接工具挺好的,看起来又好耍,图 ...
- Python 面向对象编程进阶
静态方法 只是名义上归类管理,实际上在静态方法里访问不了类或实例中的任何属性 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在 ...
- [原创]java WEB学习笔记99:Spring学习---Spring Bean配置:自动装配,配置bean之间的关系(继承/依赖),bean的作用域(singleton,prototype,web环境作用域),使用外部属性文件
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- jq 解析josn字符串
1. var obj = jQuery.parseJSON("${ruleModel.rules}"); 2. var obj = eval("("+" ...
- RobotFrameWork http/https oauth接口测试 (一)
感觉自己最近销声匿迹快一个月了,应该总结下自己这个月学习的东西了~~~折腾完公司私有协议的接口测试(c++接口),开始折腾公司的http/https接口和webservice接口的测试,想着把所有的这 ...
- 解决启动Eclipse后提示’Running android lint’错误的问题
打开项目的AndroidManifest.xml文件,android:targetSdkVersion="21"改为“20”或以下的值.由于Android L为预览版本,版本号还是 ...