Java多线程之CyclicBarrier

CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作很有用。

可能这里大家会比较疑惑CountDownLatch和CyclicBarrier究竟有什么区别??

两者主要用于多线程的并发执行。当一个线程需要等待另外一个或多个线程的执行时,就可以考虑用它俩。
 
共同点:


  • 两者的共同点是都具有await()方法,并且执行此方法会引起线程的阻塞,达到某种条件才能继续执行(这种条件也是两者的不同)。

  • 还有一个共同点是其构造方法都接受一个int类型的参数,这个值作为计数用,达到该次数即释放等待的线程。

不同点:


  • CountDownLatch是减计数方式,计数==0时释放所有等待的线程;CyclicBarrier是加计数方式,计数达到构造方法中参数指定的值时释放所有等待的线程。

  • CountDownLatch当计数到0时,计数无法被重置;CyclicBarrier计数达到指定值时,计数置为0重新开始。

  • CountDownLatch每次调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响;CyclicBarrier只有一个await()方法,调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞。
   举个很生动的例子(哈哈,自卖自夸):CountDownLatch 是计数器, 线程完成一个就记一个, 就像报数一样, 只不过是递减的. 而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.

package com.uppower.thread;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5, new TotalTask());

        // 实际系统是查出所有省编码code的列表,然后循环,每个code生成一个线程。
        new BillTask(barrier, "北京").start();
        new BillTask(barrier, "上海").start();
        new BillTask(barrier, "广西").start();
        new BillTask(barrier, "四川").start();
        new BillTask(barrier, "黑龙江").start();

    }

    static class TotalTask implements Runnable {

        public void run() {
            System.out.println("=======================================");
            System.out.println("开始全国汇总");       
            try {
                //doTotalBill() 读取内存中各省的数据汇总,过程略。
                Thread.sleep(3000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println("全国汇总完毕");       
            System.out.println("=======================================");
        }
    }

    /**
     * 子任务:计费任务
     */
    static class BillTask extends Thread {

        private CyclicBarrier barrier;

        // 代码,按省代码分类,各省数据库独立。
        private String code;

        BillTask(CyclicBarrier barrier, String code) {
            this.barrier = barrier;
            this.code = code;
        }

        public void run() {
            System.out.println("开始计算--" + code + "省--数据!");
            
            try {
                //doBill()
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            
            // 把bill方法结果存入内存,如ConcurrentHashMap,vector等,代码略
            System.out.println(code + "省已经计算完成,并通知汇总Service!");
            try {
                // 通知barrier已经完成
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(" 全国汇总完毕了--" + code + "省又可以happy了!");
        }
    }
}

运行输出结果:

开始计算--北京省--数据!
开始计算--广西省--数据!
开始计算--四川省--数据!
开始计算--上海省--数据!
开始计算--黑龙江省--数据!
北京省已经计算完成,并通知汇总Service!
广西省已经计算完成,并通知汇总Service!
黑龙江省已经计算完成,并通知汇总Service!
四川省已经计算完成,并通知汇总Service!
上海省已经计算完成,并通知汇总Service!
=======================================
开始全国汇总

全国汇总完毕
=======================================
 全国汇总完毕了--北京省又可以happy了!
 全国汇总完毕了--黑龙江省又可以happy了!
 全国汇总完毕了--广西省又可以happy了!
 全国汇总完毕了--四川省又可以happy了!
 全国汇总完毕了--上海省又可以happy了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章