zoukankan      html  css  js  c++  java
  • CyclicBarrier的介绍和使用

    转自:http://www.itzhai.com/the-introduction-and-use-of-cyclicbarrier.html

    类说明:

    一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

    CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

    public CyclicBarrier(int parties, Runnable barrierAction)
    创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
    参数:
    parties - 在启动 barrier 前必须调用 await() 的线程数
    barrierAction - 在启动 barrier 时执行的命令;如果不执行任何操作,则该参数为 null
    抛出:
    IllegalArgumentException - 如果 parties 小于 1

    使用场景:

    需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier。

    常用方法:

    public int await() throws InterruptedException,BrokenBarrierException
    在所有参与者都已经在此 barrier 上调用 await方法之前,将一直等待。如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
    最后一个线程到达;或者
    其他某个线程中断当前线程;或者
    其他某个线程中断另一个等待线程;或者
    其他某个线程在等待 barrier 时超时;或者
    其他某个线程在此 barrier 上调用 reset()。
    如果当前线程:
    在进入此方法时已经设置了该线程的中断状态;或者
    在等待时被中断则抛出 InterruptedException,并且清除当前线程的已中断状态。如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。
    如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
    如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。

    返回:
    到达的当前线程的索引,其中,索引 getParties() - 1 指示将到达的第一个线程,零指示最后一个到达的线程
    抛出:
    InterruptedException - 如果当前线程在等待时被中断
    BrokenBarrierException - 如果另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者在调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。

    相关实例

    赛跑时,等待所有人都准备好时,才起跑:

    public class CyclicBarrierTest {
        public static void main(String[] args) throws IOException, InterruptedException {
            CyclicBarrier barrier = new CyclicBarrier(3);
            ExecutorService executor = Executors.newFixedThreadPool(3);
            executor.submit(new Thread(new Runner(barrier, "1号选手")));
            executor.submit(new Thread(new Runner(barrier, "2号选手")));
            executor.submit(new Thread(new Runner(barrier, "3号选手")));
            executor.shutdown();
        }
    }
    
    class Runner implements Runnable {
        // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)
        private CyclicBarrier barrier;
        private String name;
        public Runner(CyclicBarrier barrier, String name) {
            super();
            this.barrier = barrier;
            this.name = name;
        }
        @Override
        public void run() {
            try {
                Thread.sleep(1000 * (new Random()).nextInt(8));
                System.out.println(name + " 准备好了...");
                // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(name + " 起跑!");
        }
    }
    

    当所有的CyclicBarrier调用await后,CyclicBarrier内部的控制值又回到初始设置值。
    下面举一个跟团出去玩得一个例子:在浏览下一个景点前,导游都会先统计一下人数,确定大家都到了。

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class BarrierTest {
    	
    	private static final int THREAD_COUNT = 10;
    	
    	private final static CyclicBarrier CYCLIC_BARRIER = new CyclicBarrier(THREAD_COUNT  ,
    		new Runnable() {
    			public void run() {
    				System.out.println("======>我是导游,本次点名结束,准备走下一个环节!");
    			}
    		}
    	);
    	
    	public static void main(String []args) 
    			throws InterruptedException, BrokenBarrierException {
    		for(int i = 0 ; i < 10 ; i++) {
    			new Thread(String.valueOf(i)) {
    				public void run() {
    					try {
    						System.out.println("我是线程:" + this.getName() + " 我们达到旅游地点!");
    						CYCLIC_BARRIER.await();
    						System.out.println("我是线程:" + this.getName() + " 我开始骑车!");
    						CYCLIC_BARRIER.await();
    						System.out.println("我是线程:" + this.getName() + " 我们开始爬山!");
    						CYCLIC_BARRIER.await();
    						System.out.println("我是线程:" + this.getName() + " 我们回宾馆休息!");
    						CYCLIC_BARRIER.await();
    						System.out.println("我是线程:" + this.getName() + " 我们开始乘车回家!");
    						CYCLIC_BARRIER.await();
    						System.out.println("我是线程:" + this.getName() + " 我们到家了!");
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					} catch (BrokenBarrierException e) {
    						e.printStackTrace();
    					}
    				}
    			}.start();
    		}
    	}
    }
    
  • 相关阅读:
    把git项目放到个人服务器上
    关于fcitx无法切换输入法的问题解决
    博客变迁通知
    (欧拉回路 并查集 别犯傻逼的错了) 7:欧拉回路 OpenJudge 数据结构与算法MOOC / 第七章 图 练习题(Excercise for chapter7 graphs)
    (并查集) HDU 1856 More is better
    (并查集 不太会) HDU 1272 小希的迷宫
    (并查集 注意别再犯傻逼的错了) HDU 1213 How Many Tables
    (最小生成树 Kruskal算法) 51nod 1212 无向图最小生成树
    (并查集) HDU 1232 畅通工程
    (最小生成树 Prim) HDU 1233 还是畅通工程
  • 原文地址:https://www.cnblogs.com/limingluzhu/p/4870783.html
Copyright © 2011-2022 走看看