2.9.集合点同步

来源:互联网 发布:微信淘宝客怎么做 编辑:程序博客网 时间:2024/06/06 08:34

集合点同步

上节讨论了如何实现等待并发线程完成,如果并发线程在一个节点需要等待其他的并发线程完成操作,而后才能继续处理,如何让并发线程能够在一点(这个点称之为集合点)等待其他线程?为更容易的处理这类问题,Java5引入了CyclicBarrier类,它也是一个同步辅助类,允许多个线程在某个点上进行同步。


CyclicBarrier使用一个整数进行初始化,这个数是需要在某点同步的线程数。当一个线程到达指定点后,调用await方法等待其他的线程。当线程调用await方法后,CyclicBarrier类将阻塞这个线程并使之休眠直到所有其他线程到达。当最后一个线程调用CyclicBarrierawait方法时,CyclicBarrier对象将唤醒所有在等待的线程,然后这些线程将继续执行。

重置

CyclicBarrier可以被重置回初始状态,并把它的内部计数器重置为初始化时的值。调用reset方法可以将CyclicBarrier对象重置,重置后在await方法中等待的线程将收到BrokenBarrierException异常,并发程序需要捕获此异常并作现场清理。

损坏

CyclicBarrier有一种特殊状态:损坏(Broken)。当线程在await方法上等待时如果其中一个线程被中断,这个线程抛出InterruptedException其他等待线程将抛出BrokenBarrierException异常,这时CyclicBarrier对象就处于损坏状态。CyclicBarrier的isBorken()方法可以查询是否处于损坏状态。

后处理

CyclicBarrier还有一个特性:可以传入另一个Runnable对象作为初始化参数。当所有的线程都到达集合点后,CyclicBarrier类将这个Runnable对象作为线程执行。这个特性使这个类在并行任务上很类似分治归并编程模型。


这里以查找二维数组中最大值为例来说明CyclicBarrier的作用和用法,简单起见二维数组的每一维都由一个单独线程来查找最大值,等这些线程都找出各自的最大值后,最后由归并线程从各个线程查找出来的结果中再找出最大值。示例代码如下:

public class CyclicBarrierDemo {    public static void main(String[] args){        int[][] arrays = new int[4][10];        //初始化二维数组        for(int i=0; i<arrays.length; i++){            for(int j=0;j<arrays[0].length;j++){                int tmp = (int)(Math.random() * 1000);                arrays[i][j] = tmp;            }        }        Result result = new Result();        //创建归并器        Grouper grouper = new Grouper(result);        CyclicBarrier barrier = new CyclicBarrier(arrays.length,grouper);        //创建查找线程,线程数量就是数组一维的数量        System.out.println("main:创建查找线程");        Thread[] searchThreads = new Thread[arrays.length];        for(int i=0; i<arrays.length; i++){            Searcher searcher = new Searcher(arrays[i],result, barrier);            searchThreads[i] = new Thread(searcher);        }        //启动查找线程        System.out.println("main:启动查找线程");        for(int i=0; i<arrays.length; i++){            searchThreads[i].start();        }        System.out.println("main:退出");    }}class Searcher implements Runnable{    private Result result;    private int[] arrays;    private CyclicBarrier barrier;    Searcher(int[] arrays, Result result, CyclicBarrier barrier) {        this.result = result;        this.arrays = arrays;        this.barrier = barrier;    }    @Override    public void run() {        int max = 0;        for(int value : arrays){            if(max < value){                max = value;            }        }        result.add(max);        System.out.println("Searcher," + Thread.currentThread().getName() + ":最大数是:" + max);        System.out.println("Searcher," + Thread.currentThread().getName() + ":等待其他线程");        try {            barrier.await();        } catch (InterruptedException e) {            e.printStackTrace();        } catch (BrokenBarrierException e) {            e.printStackTrace();        }        System.out.println("Searcher," + Thread.currentThread().getName() + ":退出查找");    }}class Grouper implements Runnable{    Result result;    Grouper(Result result) {        this.result = result;    }    @Override    public void run() {        System.out.println("Grouper:开始归并");        int max = 0;        List<Integer> values = result.getAll();        for(int value : values){            if(max < value){                max = value;            }        }        System.out.println("Grouper:最大数是:" + max);        System.out.println("Grouper:退出归并");    }}/** 结果保存类 **/class Result{    private List<Integer> result = new ArrayList<Integer>(10);    public synchronized void add(int i){        result.add(i);    }    public List<Integer> getAll(){        return result;    }}

程序运行日志:

main:创建查找线程main:启动查找线程main:退出Searcher,Thread-0:最大数是:953Searcher,Thread-0:等待其他线程Searcher,Thread-2:最大数是:963Searcher,Thread-2:等待其他线程Searcher,Thread-3:最大数是:831Searcher,Thread-3:等待其他线程Searcher,Thread-1:最大数是:973Searcher,Thread-1:等待其他线程Grouper:开始归并Grouper:最大数是:973Grouper:退出归并Searcher,Thread-0:退出查找Searcher,Thread-2:退出查找Searcher,Thread-3:退出查找Searcher,Thread-1:退出查找



0 0
原创粉丝点击