• Java核心-多线程(7)-并发控制器-CyclicBarrier同步屏障


    1.基本概念
    中文译本同步屏障,同样来自jdk并发工具包中一个并发控制器,它的使用和CountDownLatch有点相似,能够完成某些相同并发场景,但是它们却不相同。

    2.抽象模型
    主要用来实现多个线程同步,同步后可能唤醒另外一个任务,然后继续执行线程后面的任务。CountDownLatch抽象模型却是一个或多个线程通知某个或多个线程,它没有同步功能。

    3.使用场景
    田径比赛, 虽然上一篇文章使用CountDownLatch也能实现,但是我觉得这里却使用同步屏障更简单点。

    4.CyclicBarrier使用api
    java new CyclicBarrier(int parties); //创建同步屏障,仅仅启动同步作用,中间没有需要执行的任务。
    java new CyclicBarrier(int parties, Runnable barrierAction); //创建同步屏障,不仅同步,而且中间有任务需要执行。
    java cyclicBarrier.await(); //调用一次,parties就会减1,直到变为0时,执行barrierAction任务后(配置情况下),然后执行此代码的线程才能停止阻塞,继续执行。
    java ps:因为使用CyclicBarrier的线程都会阻塞在await方法上,所以在线程池中使用CyclicBarrier时要特别小心,如果线程池的线程过少,那么就会发生死锁了。

    5.使用示例(田径比赛)

        public static void main(String[] args) {
    		ExecutorService executor = Executors.newFixedThreadPool(3);
    		final CyclicBarrier startBarrier = new CyclicBarrier(3, new Runnable() {
    			@Override
    			public void run() {
    				
    				try {
    					System.out.println("他们都准备好了,那就开跑吧");
    					System.out.println("3");
    					Thread.sleep(1000);
    					System.out.println("2");
    					Thread.sleep(1000);
    					System.out.println("1");
    					Thread.sleep(1000);
    					System.out.println("0");
    					System.out.println("go!!!");
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		});
    		CyclicBarrier endBarrier = new CyclicBarrier(3, new Runnable() {
    			@Override
    			public void run() {
    				System.out.println("都到达了终点,比赛结束");
    			}
    		});
    		for(int i=3;i>0;i--){
    			final int num = i;
    			Runnable runnable = new Runnable() {
    				
    				@Override
    				public void run() {
    					try {
    						int time = (int)(Math.random()*1000);
    						Thread.sleep(time);
    						System.out.println("运动员" + num + "号,准备了" + time + "ms,准备结束!");
    						startBarrier.await();
    						System.out.println("运动员" + num + "号,开始跑了");
    						int runtime = (int)(Math.random()*10000);
    						Thread.sleep(runtime);
    						System.out.println("运动员" + num + "号,用时:" + runtime + "ms");
    						endBarrier.await();
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    			};
    			executor.submit(runnable);
    		}
    	}
    

    执行结果

    运动员1号,准备了580ms,准备结束!
    运动员3号,准备了866ms,准备结束!
    运动员2号,准备了878ms,准备结束!
    他们都准备好了,那就开跑吧
    3
    2
    1
    0
    go!!!
    运动员2号,开始跑了
    运动员1号,开始跑了
    运动员3号,开始跑了
    运动员2号,用时:2008ms
    运动员3号,用时:5587ms
    运动员1号,用时:6634ms
    都到达了终点,比赛结束
    

    6.和CountDownLatch的区别
    <1>CountDownLatch能唤醒多个线程,而CyclicBarrier只能唤醒一个线程;
    <2>一个线程或多个线程(A)使用CountDownLatch通知另外一个或多个线程(B),A线程之间不会有同步功能,需要多个latch才能实现同步功能;而CyclicBarrier能同步A线程组的执行步骤;
    <3>CountDownLatch是一次性的,不能重置,而CyclicBarrier不是,它有reset()方法;

  • 相关阅读:
    Haskell Interactive Development in Emacs
    Access Java API in Groovy Script
    手工设置Eclipse文本编辑器的配色
    Color Theme of Emacs
    Gnucash的投资记录
    Special Forms and Syntax Sugars in Clojure
    Use w3m as Web Browser
    SSE指令集加速之 I420转BGR24
    【图像处理】 增加程序速度的方法
    TBB 入门笔记
  • 原文地址:https://www.cnblogs.com/leeethan/p/10680835.html
Copyright © 2020-2023  润新知