Java--CyclicBarrier使用简介

CyclicBarrier介绍 (一)

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

  主要使用方法:

//设置parties、count及barrierCommand属性。
CyclicBarrier(int):   

//当await的数量到达了设定的数量后,首先执行该Runnable对象。
CyclicBarrier(int,Runnable):   

//通知barrier已完成线程
await():

应用场景
  在某种需求中,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行  主任务,这时候,就可以选择CyclicBarrier了。

实例分析
  我们需要统计全国的业务数据。其中各省的数据库是独立的,也就是说按省分库。并且统计的数据量很大,统计过程也比较慢。为了提高性能,快速计算。我们采取并发的方式,多个线程同时计算各省数据,最后再汇总统计。在这里CyclicBarrier就非常有用。看代码:
主要类:

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

import utils.Tools.BillService;
import utils.Tools.TotalService;

    /**
     * 各省数据独立,分库存偖。为了提高计算性能,统计时采用每个省开一个线程先计算单省结果,最后汇总。
     *
     */
    public class Total {   

        // private ConcurrentHashMap result = new ConcurrentHashMap();   

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

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

        }
    }   

    /**
     * 主任务:汇总任务
     */
    class TotalTask implements Runnable {
        private TotalService totalService;   

        TotalTask(TotalService totalService) {
            this.totalService = totalService;
        }   

        public void run() {
            // 读取内存中各省的数据汇总,过程略。
            totalService.count();
            System.out.println("=======================================");
            System.out.println("开始全国汇总");
        }
    }   

    /**
     * 子任务:计费任务
     */
    class BillTask extends Thread {
        // 计费服务
        private BillService billService;
        private CyclicBarrier barrier;
        // 代码,按省代码分类,各省数据库独立。
        private String code;   

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

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

    }  
import utils.Tools.BillService;

public class BillServiceImpl implements BillService {

    @Override
    public void bill(String code) {
        // TODO Auto-generated method stub

    }

}
import utils.Tools.TotalService;

public class TotalServiceImpl implements TotalService{

        @Override
        public void count() {
            // TODO Auto-generated method stub

        }

    }
package utils;

public class Tools {
    /**
     *
     */
    public interface BillService {

        /**
         * 各省计费
         *
         * @param code
         *            省编码
         */
        public void bill(String code);

    }

    /**
     *
     */
    public interface TotalService {

        /**
         * 汇总各省数据
         */
        public void count();

    }

}

结果:

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

CyclicBarrier介绍 (二)

张孝祥视频学习笔记:

CyclicBarrier 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在i指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐……

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

public class CyclicBarrierTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final CyclicBarrier cb = new CyclicBarrier(3); // 三个线程同时到达
        for (int i = 0; i < 3; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "即将到达集合地点1,当前已有"
                                + (cb.getNumberWaiting() + 1)
                                + "个已到达"
                                + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        try {
                            cb.await();
                        } catch (BrokenBarrierException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "即将到达集合地点2,当前已有"
                                + (cb.getNumberWaiting() + 1)
                                + "个已到达"
                                + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        try {
                            cb.await();
                        } catch (BrokenBarrierException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("线程"
                                + Thread.currentThread().getName()
                                + "即将到达集合地点3,当前已有"
                                + (cb.getNumberWaiting() + 1)
                                + "个已到达"
                                + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊"
                                        : "正在等候"));
                        try {
                            cb.await();
                        } catch (BrokenBarrierException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }
        service.shutdown();
    }
}

输出结果

线程pool-1-thread-3即将到达集合地点1,当前已有1个已到达正在等候
线程pool-1-thread-2即将到达集合地点1,当前已有2个已到达正在等候
线程pool-1-thread-1即将到达集合地点1,当前已有3个已到达都到齐了,继续走啊
线程pool-1-thread-1即将到达集合地点2,当前已有1个已到达正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有2个已到达正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有3个已到达都到齐了,继续走啊
线程pool-1-thread-3即将到达集合地点3,当前已有1个已到达正在等候
线程pool-1-thread-1即将到达集合地点3,当前已有2个已到达正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有3个已到达都到齐了,继续走啊

CyclicBarrier介绍 (三)

  旅游,导游带队,只有在全部成员到齐的时候,导游才会下达去下一个景点的通知。

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Travel {
    private static final int THREAD_COUNT = 3;
//  当THREAD_COUNT 逐个减到0的时候,就开是执行runnable
    private final static CyclicBarrier CYSLIC_BARRIER = new CyclicBarrier(
            THREAD_COUNT, new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    System.out.println("我是导游,本次点名结束,准备下一个景点。");
                }
            });

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(String.valueOf(i)){
                public void run() {
                    try {
                        System.out.println("我是线程"+ this.getName()+",我们到达旅游景点。");
                        CYSLIC_BARRIER.await();
                        System.out.println("我是线程"+ this.getName()+",我们开始骑车。");
                        CYSLIC_BARRIER.await();
                        System.out.println("我是线程"+ this.getName()+",我们开始爬山。");
                        CYSLIC_BARRIER.await();
                        System.out.println("我是线程"+ this.getName()+",我们回宾馆休息。");
                        CYSLIC_BARRIER.await();
                        System.out.println("我是线程"+ this.getName()+",我们骑车回家。");
                        CYSLIC_BARRIER.await();
                        System.out.println("我是线程"+ this.getName()+",我们到家了。");
                        CYSLIC_BARRIER.await();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                };
            }.start();
        }
    }

}

结果:

我是线程2,我们到达旅游景点。
我是线程0,我们到达旅游景点。
我是线程1,我们到达旅游景点。
我是导游,本次点名结束,准备下一个景点。
我是线程1,我们开始骑车。
我是线程0,我们开始骑车。
我是线程2,我们开始骑车。
我是导游,本次点名结束,准备下一个景点。
我是线程2,我们开始爬山。
我是线程0,我们开始爬山。
我是线程1,我们开始爬山。
我是导游,本次点名结束,准备下一个景点。
我是线程1,我们回宾馆休息。
我是线程0,我们回宾馆休息。
我是线程2,我们回宾馆休息。
我是导游,本次点名结束,准备下一个景点。
我是线程2,我们骑车回家。
我是线程0,我们骑车回家。
我是线程1,我们骑车回家。
我是导游,本次点名结束,准备下一个景点。
我是线程1,我们到家了。
我是线程0,我们到家了。
我是线程2,我们到家了。
我是导游,本次点名结束,准备下一个景点。
时间: 2024-10-05 05:41:39

Java--CyclicBarrier使用简介的相关文章

java.util.Calendar简介

java.util.Calendar简介 一般写为:import java.util.Calendar;在开头 然后在中间写上, Calendar cal = Calendar.getInstance(); int year=cal.get(Calendar.YEAR); int month=cal.get(Calendar.MONTH);就可以了: Calendar是一个抽象类,我们无法直接实例化它,它有一个具体子类实体类java.util.GregorianCalendar,这个类实现的就是

java反射机制简介

1.字节码.所谓的字节码就是当java虚拟机加载某个类的对象时,首先需要将硬盘中该类的源代码编译成class文件的二进制代码(字节码),然后将class文件的字节码加载到内存中,之后再创建该类的对象 2.java反射的基础是Class类(注意不是小写的class),Class类实例代表着内存中的一份字节码.常见的获取Class类对象的方法如下(第一种为对象的方法,第二种为类的方法): Dog dog = new Dog(); Class dogClass = dog.getClass(); Cl

[Java 8 Lambda] java.util.stream 简介

包结构如下所示: 这个包的结构很简单,类型也不多. BaseStream接口 所有Stream接口类型的父接口,它继承自AutoClosable接口,定义了一些所有Stream都具备的行为. 因为继承自AutoClosable接口,所以所有的Stream类型都可以用在Java 7中引入的try-with-resource机制中,以达到自动关闭资源的目的.实际上,只有当Stream是通过Socket,Files IO等方式创建的时候,才需要关闭它.对于来自于Collections,Arrays的S

JAVA线程池简介

一 简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的问题提供了非常大的帮助. 二 线程池线程池的作用: 线程池作用就是限制系统中执行线程的数量.根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率

【Java】Java Servlet 技术简介

Java 开发人员兼培训师 Roy Miller 将我们现有的 servlet 介绍资料修改成了这篇易于学习的实用教程.Roy 将介绍并解释 servlet 是什么,它们是如何工作的,如何使用它们来创建您能够想像到的任意复杂度的 Web 应用程序,以及作为一名专业编程人员,您如何才能最有效地使用 servlet. 5 评论: Roy W. Miller ([email protected]), 独立的软件开发辅导员.程序员和作者, RoleModel Software 2004 年 12 月 2

Java -- Java 新 IO -- Java 新IO简介

20.1 Java 新IO简介 20.2 缓冲区与Buffer 例:演示缓冲区的操作流程 Class : IntBufferDemo01 20.2.2 深入缓冲区操作 20.2.3 创建子缓冲区 20.2.4 创建只读缓冲区 20.2.5 创建直接缓冲区 20.3 通道 20.3.1 FileChannel 例:使用输出通道输出内容 Class : FileChannelDemo01 例:使用通道进行读写操作 Class :FileChannelDemo02 20.3.2 内存映射 例:内存映射

Java Servlet 技术简介

Java Servlet 技术简介 Java 开发人员兼培训师 Roy Miller 将我们现有的 servlet 介绍资料修改成了这篇易于学习的实用教程.Roy 将介绍并解释 servlet 是什么,它们是如何工作的,如何使用它们来创建您能够想像到的任意复杂度的 Web 应用程序,以及作为一名专业编程人员,您如何才能最有效地使用 servlet. 4 评论: Roy W. Miller ([email protected]), 独立的软件开发辅导员.程序员和作者, RoleModel Soft

Java基础类库简介

Java基础类库简介 一.常用的基础类库:11个jar(Java Archive,Java归档)包 作为java语言使用者,我们可以感受到java语言带来的优势(平台无关.面向对象.多线程.高效易扩展等),而且它有很多已经实现的类库可以供我们直接使用,这些类库都是以jar包的形式提供的,也可以成为java API,它为编程者实现了各种常用操作的方法,为程序员编写java程序代码带来了许多方便. 作为初学者,我觉得熟练掌握和应用java基础类库是很有必要的.因此,总结了一些自己在初学java时的一

Java多线程概念简介 多线程中篇(一)

Java的线程与操作系统的线程 在线程的相关介绍中,有讲到“线程的实现”分为三种:内核支持,用户级以及两者混合.(这只是一种简要的分类) Java线程在JDK1.2之前,是用户线程实现的 而在JDK1.2中,线程模型变为基于操作系统原生线程模型来实现的 所以说Java虚拟机中线程的映射实现,是受制于操作系统的,操作系统支持怎样的线程模型,决定了Java虚拟机中线程的样子. 虚拟机规范中也并未限定Java线程需要使用哪种线程模型来实现. 线程模型只对线程的并发规模和操作成本产生影响,对Java程序

java CyclicBarrier同步屏障

CyclicBarrier的字面意思是可循环使用的屏障,它的主要作用是,让一组线程到达一个屏障时被阻塞,知道最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续运行. 1.简介: CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其中参数标识屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞. package com.test; import java.util.concur