CyclicBarrier的使用

来源:互联网 发布:淘宝千里眼软件怎么样 编辑:程序博客网 时间:2024/05/17 06:04

简介

CyclicBarrier与CountDownLatch都是在jdk1.5时引入,存在于java.util.concurrent包下。CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。CyclicBarrier的作用是让一组线程之间相互等待,任何一个线程到达屏障点后就阻塞,直到最后一个线程到达,才都继续往下执行。
如:需要统计多个文件中每个单词出现次数,可以多个线程同时读取文件,将单个文件中单词分别计数、保存并等待其他文件被读取,直到最后一个文件被读取、分组结束。各个线程分别从各自分组再次读取信息,进行后续合并计算。如下图:
这里写图片描述
注:每种颜色的线代表一个线程,大致流程:每个线程读取对应文件,并将文件中内容按单词分类统计,并将分类统计结果保存到分组文件中,此后等待其他分组线程执行结束,然后进行统计汇总,将结果写入到一个文件中。分类算法可以使用最简单的hash求模,保证生成分组文件数量与线程数量相同。

实现

工作类:

package com.leiyu.bootdemo.knowleadge;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.TimeUnit;/** * Created by wanghao30 on 2017/9/7. */public class WorkerOther extends Thread {    private CyclicBarrier cyclicBarrier ;    private CountDownLatch countDownLatch;    private int threadnum;    private Random random = new Random(10l);    public WorkerOther(CyclicBarrier cyclicBarrier,CountDownLatch countDownLatch, int threadnum){        this.cyclicBarrier = cyclicBarrier;        this.countDownLatch = countDownLatch;        this.threadnum = threadnum;    }    @Override    public void run() {       try {           TimeUnit.SECONDS.sleep(random.nextInt(10));           System.out.println("线程:" + Thread.currentThread().getName() + "读取原文件并分组完毕,等待其他线程读取并分组!");           cyclicBarrier.await();           TimeUnit.SECONDS.sleep(random.nextInt(10));           System.out.println("线程:" + Thread.currentThread().getName() + "从汇总文件中获取前5名,等待其他线程读取并分组!");           cyclicBarrier.await();           TimeUnit.SECONDS.sleep(random.nextInt(10));           System.out.println("线程:" + Thread.currentThread().getName() + "读取分组文件并汇总完毕,告知主线程!");           this.countDownLatch.countDown();           System.out.println("线程:" + Thread.currentThread().getName() + "执行完毕");       }catch (Exception e){       }    }}

主函数:

public class CyclicBarrierMain {    private static int threadNums = 4;    public static void main(String[] args) throws InterruptedException {        CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNums);        CountDownLatch countDownLatch = new CountDownLatch(threadNums);        for(int i = 0 ; i < threadNums ; i++){            new WorkerOther(cyclicBarrier,countDownLatch,threadNums).start();        }        countDownLatch.await();        System.out.println("主线程执行完毕!");    }}

输出:

线程:Thread-0读取原文件并分组完毕,等待其他线程读取并分组!线程:Thread-3读取原文件并分组完毕,等待其他线程读取并分组!线程:Thread-2读取原文件并分组完毕,等待其他线程读取并分组!线程:Thread-1读取原文件并分组完毕,等待其他线程读取并分组!线程:Thread-1从汇总文件中获取前5名,等待其他线程读取并分组!线程:Thread-0从汇总文件中获取前5名,等待其他线程读取并分组!线程:Thread-2从汇总文件中获取前5名,等待其他线程读取并分组!线程:Thread-3从汇总文件中获取前5名,等待其他线程读取并分组!线程:Thread-0读取分组文件并汇总完毕,告知主线程!线程:Thread-0执行完毕线程:Thread-2读取分组文件并汇总完毕,告知主线程!线程:Thread-1读取分组文件并汇总完毕,告知主线程!线程:Thread-1执行完毕线程:Thread-2执行完毕线程:Thread-3读取分组文件并汇总完毕,告知主线程!线程:Thread-3执行完毕主线程执行完毕!

注意事项

  1. 线程await后,后续操作不再进行,直到其他所有线程到达栅栏才会执行后续操作
  2. 调用reset后,屏障重置为初始状态。重置屏障时,可能会导致一个正在等待的线程抛出BrokenBarrierException异常

与CountDownLatch对比

  1. CountDownLatch是一个线程等待多个线程执行完任务之后,这个任务执行后续操作。CyclicBarrier是多个线程彼此相互等待。直到所有线程到达等待位置,则同时开启,完成后续操作
  2. CountDownLatch是不可重复试用的,计数器归零后就不能再次使用。CyclicBarrier可以重复使用,并提供reset方法。
原创粉丝点击