浏览 8608 次
锁定老帖子 主题:并发编程一波流之CyclicBarrier
精华帖 (0) :: 良好帖 (6) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-30
最后修改:2011-03-30
CyclicBarrier介绍
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。 主要方法: //设置parties、count及barrierCommand属性。 CyclicBarrier(int): //当await的数量到达了设定的数量后,首先执行该Runnable对象。 CyclicBarrier(int,Runnable): //通知barrier已完成线程 await(): 应用场景 在某种需求中,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择CyclicBarrier了。 实例分析 我们需要统计全国的业务数据。其中各省的数据库是独立的,也就是说按省分库。并且统计的数据量很大,统计过程也比较慢。为了提高性能,快速计算。我们采取并发的方式,多个线程同时计算各省数据,最后再汇总统计。在这里CyclicBarrier就非常有用。看代码: 主要类: /** * 各省数据独立,分库存偖。为了提高计算性能,统计时采用每个省开一个线程先计算单省结果,最后汇总。 * * @author guangbo email:weigbo@163.com * */ public class Total { // private ConcurrentHashMap result = new ConcurrentHashMap(); public static void main(String[] args) { TotalService totalService = new TotalServiceImpl(); CyclicBarrier barrier = new CyclicBarrier(5, new TotalTask(totalService)); // 实际系统是查出所有省编码code的列表,然后循环,每个code生成一个线程。 new BillTask(new BillServiceImpl(), barrier, "北京").start(); new BillTask(new BillServiceImpl(), barrier, "上海").start(); new BillTask(new BillServiceImpl(), barrier, "广西").start(); new BillTask(new BillServiceImpl(), barrier, "四川").start(); new BillTask(new BillServiceImpl(), barrier, "黑龙江").start(); } } /** * 主任务:汇总任务 */ class TotalTask implements Runnable { private TotalService totalService; TotalTask(TotalService totalService) { this.totalService = totalService; } public void run() { // 读取内存中各省的数据汇总,过程略。 totalService.count(); System.out.println("======================================="); System.out.println("开始全国汇总"); } } /** * 子任务:计费任务 */ class BillTask extends Thread { // 计费服务 private BillService billService; private CyclicBarrier barrier; // 代码,按省代码分类,各省数据库独立。 private String code; BillTask(BillService billService, CyclicBarrier barrier, String code) { this.billService = billService; this.barrier = barrier; this.code = code; } public void run() { System.out.println("开始计算--" + code + "省--数据!"); billService.bill(code); // 把bill方法结果存入内存,如ConcurrentHashMap,vector等,代码略 System.out.println(code + "省已经计算完成,并通知汇总Service!"); try { // 通知barrier已经完成 barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } 结果: 开始计算--北京省--数据! 开始计算--上海省--数据! 北京省已经计算完成,并通知汇总Service! 开始计算--四川省--数据! 四川省已经计算完成,并通知汇总Service! 上海省已经计算完成,并通知汇总Service! 开始计算--广西省--数据! 广西省已经计算完成,并通知汇总Service! 开始计算--黑龙江省--数据! 黑龙江省已经计算完成,并通知汇总Service! ======================================= 开始全国汇总 其它业务类 /** * @author guangbo * */ public interface BillService { /** * 各省计费 * * @param code * 省编码 */ public void bill(String code); } /** * @author guangbo * */ public interface TotalService { /** * 汇总各省数据 */ public void count(); } 实例讲解,力求简单易懂,高效实用。欢迎拍砖,谢绝漫骂。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-03-31
不错 以前我是一个个设标志位,每个线程执行完后更新各自的标志位,如果都齐了就执行。不过终止或者异常的处理就相当麻烦
用这玩意应该更方便些 |
|
返回顶楼 | |
发表时间:2011-06-20
问下楼主,既然5个省的计算数据都是只运行一次为什么一定要用多线程呢,个人感觉除了Total 类需要定时启动数据计算用到线程外,其余省的计算不需要线程控制,如果不是线程去完成任务,那么就有好多方法去控制业务顺序了(当5个省运行完再执行总局汇总)
|
|
返回顶楼 | |
发表时间:2011-09-24
确实解释的很容易让人理解,感觉楼主写的代码分层得好清晰啊,
|
|
返回顶楼 | |
发表时间:2011-09-24
最后修改:2011-09-24
java.util.concurrent包里面
关于公共栅栏的类貌似有两个,这个类和另外一个轻量级一点的。 这个可以reset、另外一个不可以reset |
|
返回顶楼 | |
发表时间:2011-09-26
我怎么觉得用countdown更适合这个场景呢
|
|
返回顶楼 | |
发表时间:2011-09-28
busiying119 写道 问下楼主,既然5个省的计算数据都是只运行一次为什么一定要用多线程呢,个人感觉除了Total 类需要定时启动数据计算用到线程外,其余省的计算不需要线程控制,如果不是线程去完成任务,那么就有好多方法去控制业务顺序了(当5个省运行完再执行总局汇总)
多线程是为了节省时间 |
|
返回顶楼 | |
发表时间:2011-11-11
java_user 写道 busiying119 写道 问下楼主,既然5个省的计算数据都是只运行一次为什么一定要用多线程呢,个人感觉除了Total 类需要定时启动数据计算用到线程外,其余省的计算不需要线程控制,如果不是线程去完成任务,那么就有好多方法去控制业务顺序了(当5个省运行完再执行总局汇总)
多线程是为了节省时间 好文哈,主要是能够充分的利用多核CPU,提高性能,也节省了时间。 |
|
返回顶楼 | |
发表时间:2012-03-20
yangelhun 写道 我怎么觉得用countdown更适合这个场景呢
+1 |
|
返回顶楼 | |
发表时间:2012-03-21
似乎没有循环利用CyclicBarrier么,确实CountDownLatch比CyclicBarrier更适合这个场景
|
|
返回顶楼 | |