您的位置:买球网站 > 篮球相关 > 信誉买球网站:大白话说java并发工具类,Java并发

信誉买球网站:大白话说java并发工具类,Java并发

发布时间:2019-08-21 19:58编辑:篮球相关浏览(191)

    信誉买球网站 1

    信誉买球网站 2

    首先大家来兑现二个效应:当大家运维多少个种类的时候须求初叶化许非常多量,那时候我们可能须要运行很二十四线程来扩充多少的开始化,独有那个系统起先化甘休现在能力够运维系统。其实在Java的类库中曾经提供了Semaphore、CountDownLatch、Cyclic巴里r那3个类来帮我们贯彻那样看似的效应了。

    概述

    JDK中提供了一部分用来线程之间联合等待的工具类,CountDownLatch和CyclicBarrier正是最赞叹不己的多个线程同步协理类。上面分别详细介绍那三个类,以及他们中间的异同点。

    同学们陆陆续续会弄混CountDownLatch和CyclicBarrier的施用处境或许说是否相仿压根未有场景使用到那八个工具。大家前几日就透过轻巧有意思的方法来聊一聊这三个工具的采用情况。运动会

    在八线程同盟完结工作职能时,有的时候候必要拭目以俟别的三个线程完结职分之后,主线程才干承继往下举行工作作用,在这种的事情场景下,日常能够采取Thread类的join方法,让主线程等待被join的线程实行完事后,主线程技术三翻五次往下进行。当然,使用线程间音讯通讯机制也得以形成。其实,java并发工具类中为我们提供了看似“倒计时”那样的工具类,能够特别利于的形成所说的这种工作场景。

    一、信号灯 Semaphore

    Semaphore sp = new Semaphore(int permits) 接受一个整数型的参数,表示有几盏灯。线程能够由此semaphore.acquire()获取一盏时限信号灯,通过semaphore.release()释放。它与 Lock 的差别正是 Lock 只可以是一个锁,而 Semaphore 更疑似四个锁的一个集聚,像一个打断队列同样,当队列中的锁用完了,而你又供给锁的时候,你就非得等待其余的线程释放锁。

    下边我们申明了唯有 1 个灯的实信号灯,然后运营 3 个线程相同的时间去获得数字信号灯,别的还运转了 1 个线程每 2 秒就释放一遍数字信号灯。

    /**
     * Semaphore 实现信号灯
     * @author chenyr
     * @time 2014-12-24 下午08:13:32
     * All Rights Reserved.
     */
    public class Semaphore1 {
    
        public static void main(String[] args) {
            final Semaphore sp = new Semaphore(1);  //只声明一盏信号灯
            //业务线程1
            new Thread(new Runnable(){
                public void run(){
                    try{
                        System.out.println(Thread.currentThread().getName()   "准备获取信号灯-A");
                        sp.acquire();  //获取信号灯
                        System.out.println(Thread.currentThread().getName()   "已获取信号灯-A");
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }).start();
            //业务线程2
            new Thread(new Runnable(){
                public void run(){
                    try{
                        System.out.println(Thread.currentThread().getName()   "准备获取信号灯-B");
                        sp.acquire();  //获取信号灯
                        System.out.println(Thread.currentThread().getName()   "已获取信号灯-B");
                    }catch(Exception e){
                    e.printStackTrace();
                    }
                }
            }).start();
            //业务线程3
            new Thread(new Runnable(){
                public void run(){
                    try{
                        System.out.println(Thread.currentThread().getName()   "准备获取信号灯-C");
                        sp.acquire();  //获取信号灯
                        System.out.println(Thread.currentThread().getName()   "已获取信号灯-C");
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }).start();
            //检查线程
            new Timer().schedule(new TimerTask(){
                public void run(){
                    System.out.println("每10s释放一次信号灯");
                    sp.release();
                    System.out.println("信号灯已释放");
                }
            }, 2000, 2000);    //每2秒释放一次信号灯
        }
    }
    

    实践结果如下:

    Thread-0准备获取信号灯-A
    Thread-0已获取信号灯-A
    Thread-1准备获取信号灯-B
    Thread-2准备获取信号灯-C
    每2s释放一次信号灯
    信号灯已释放
    Thread-1已获取信号灯-B
    每2s释放一次信号灯
    信号灯已释放
    Thread-2已获取信号灯-C
    每2s释放一次信号灯
    信号灯已释放
    

    从结果可以看到一发轫 Thread-0 获得了锁,Thread-1 和 Thread-2 都在守候获取,直到检查线程 2 秒后释放能量信号灯,Thread-1 才获得了能量信号灯。而 Thread-2 是在自笔者研究线程再一次释放锁的时候得到到的。

    CountDownLatch类

    CountDownLatch看名称就能够想到其意义:倒计数锁存器。没有错,他就是八个计数器,而且是倒着计数的。他的选拔场景如下:

    二个职务A,他索要等待其余的片段职分都试行实现之后它技能实施。就比如说赛跑的时候,发令员供给拭目以俟全数选手都筹划好了能力一声令下,否则不被K才怪嘞!

    那儿CountDownLatch就可以大展身手了。

    小明班级要进行运动会了。运动会最关键的是何人啊,当然是运动员和判决了。至于赛项,大家那边首要斟酌两类竞技

    为了可以知情CountDownLatch,举叁个很浅显的事例,运动员实行跑步竞技时,要是有6个选手参预竞技,评判员在顶峰会为那6个选手分别计时,能够想象没当三个运动员达到极限的时候,对于评判来讲就少了一个计时任务。直到全体选手都到达顶峰了,评判员的任务也才水到渠成。那6个选手能够类比成6个线程,当线程调用CountDownLatch.countDown方法时就能对计数器的值减一,直到计数器的值为0的时候,评判员(调用await方法的线程)能力三番五次往下实行。

    二、倒计时门栓 CountDownLatch

    经受二个整数型的参数,能够通过countDownLatch.countDown()降低三个计时,countDownLatch.await()举办线程等待,等到countDownLatch中的计数到0之后就能够余烬复起实施。CountDownLatch 与 Semaphore 的机能完全两样,CountDownLatch 是周围于会集点的贰个类,当调用者达到一个数量就能够触发一些操作。而 Semaphore 是叁个接近于锁队列的事物,锁用完了不畏用完了,而不会触发操作。

    下边大家模拟跑步竞技的事例,用 3 个线程分别模拟 3 个运动员。而那之中有 3 个节点,分别是:

    1、要等 3 个选手都准备好了,评判工夫发开跑命令

    2、3 个运动员要等评判发令工夫跑

    3、评判员要等 3 个选手都到终点了能力发布成绩

    这 3 个时刻点我们独家用二个 CountDownLatch 对象来表示,具体落实如下。

    /**
     * CountDownLatch同步工具
     * 实例:模拟运动员跑步的例子(等待裁判发令,3个运动员才跑。等到3个运动员都跑完了,裁判才宣布成绩)
     * @author chenyr
     * @time 2014-12-25 下午07:49:25
     * All Rights Reserved.
     */
    public class CountDownLatch1 {
    
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
    
            //要等到3个运动都准备好了,裁判才能命令
            final CountDownLatch waitCd = new CountDownLatch(3);
            //裁判发1次命令,运动员就开始跑
            final CountDownLatch orderCd = new CountDownLatch(1);
            //要等到3个运动员到达终点,裁判才公布成绩
            final CountDownLatch scoreCd = new CountDownLatch(3);  
    
            //模拟3个运动员
            for(int i = 1; i <= 3; i  ){
                final int count = i;
                Runnable runnable = new Runnable(){
                    public void run(){
                        try{
                            System.out.println("运动员"   count   "站在起跑线准备比赛了!");
                            waitCd.countDown(); //准备好
                            orderCd.await();
    
                            Thread.sleep((long)(Math.random() * 10000));  //模拟运动员隔多久听到命令
                            System.out.println("运动员"   count   "听到开跑命令,开跑!");
    
                            Thread.sleep((long)(Math.random() * 10000));  //模拟运动员用多长时间跑到终点
                            System.out.println("运动员"   count   "跑到了终点!");
                            scoreCd.countDown();  //跑到终点
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                };
                service.execute(runnable);
            }
    
            //模拟裁判
            Runnable runnable = new Runnable(){
                public void run(){
                    try{
                        System.out.println("裁判已到位,正在等待运动员做好准备!");
                        waitCd.await();
                        System.out.println("所有运动员已经就位,裁判准备发令!");
                        Thread.sleep((long)(Math.random() * 10000));  //模拟裁判的准备时间
                        System.out.println("裁判:比赛开始! 跑!跑!跑!");
                        orderCd.countDown();    //开跑
                        scoreCd.await();
                        System.out.println("所有运动员已经到达终点,裁判宣布成绩!");
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
    
            service.shutdown();
        }
    }
    

    运营结果如下:

    运动员2站在起跑线准备比赛了!
    运动员3站在起跑线准备比赛了!
    裁判已到位,正在等待运动员做好准备!
    运动员1站在起跑线准备比赛了!
    所有运动员已经就位,裁判准备发令!
    裁判:比赛开始! 跑!跑!跑!
    运动员1听到开跑命令,开跑!
    运动员2听到开跑命令,开跑!
    运动员1跑到了终点!
    运动员3听到开跑命令,开跑!
    运动员2跑到了终点!
    运动员3跑到了终点!
    所有运动员已经到达终点,裁判宣布成绩!
    

    常用操作

    本节介绍CountDownLatch的基本操作函数。

    一种是赛跑类型,必要凑满一堆技艺开赛,运动员们要相互等待就位后一并跑,然后本领博取结果。

    上面来看些CountDownLatch的有个别根本措施。

    三、栅栏  CyclicBarrier

    Cyclic巴里r cb = new CyclicBarrier(int parties) 接受贰个整数型的参数。线程能够经过cb.await()等待,只要正在守候的线程数目达到设定的参数,全体等待的线程就能上涨实践。CyclicBarrier 与 CountDownLatch 相似,都以要达到同等的食指工夫够进行有个别操作,只但是CountDownLatch 是减操作,而 CyclicBarrier 是加操作。与 CyclicBarrier 相似的事件是集结点,即大家 5 个人周天伙同去爬山,大家大家都要在有些地方等 5 个人到齐了再启程。

    上边安装了三个群集点,唯有当整个人到齐了第叁个会集点之后,才会持续前往下几个会集点。

    /**
     * CyclicBarrier同步工具
     * 等待所有线程到达之后再继续执行
     * @author chenyr
     * @time 2014-12-25 下午07:30:00
     * All Rights Reserved.
     */
    public class CyclicBarrier1 {
    
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            final CyclicBarrier cb = new CyclicBarrier(3);  //一共要等到几个线程才继续执行
            for(int i = 1; i <= 3; i  ){
                Runnable runnable = new Runnable(){
                    public void run(){
                        try{
                            Thread.sleep((long)(Math.random() * 10000));
                            System.out.println(Thread.currentThread().getName()   "已经到达集合点A,正在等待。目前已有"   (cb.getNumberWaiting()   1)   "个线程在等待" );
                            cb.await();
                            System.out.println("全部线程到达A集合点");
    
                            Thread.sleep((long)(Math.random() * 10000));
                            System.out.println(Thread.currentThread().getName()   "已经到达集合点B,正在等待。目前已有"   (cb.getNumberWaiting()   1)   "个线程在等待" );
                            cb.await();
                            System.out.println("全部线程到达B集合点");
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                    }
                };
                service.execute(runnable);
            }
        }
    }
    

    运行结果如下:

    pool-1-thread-2已经到达集合点A,正在等待。目前已有1个线程在等待
    pool-1-thread-1已经到达集合点A,正在等待。目前已有2个线程在等待
    pool-1-thread-3已经到达集合点A,正在等待。目前已有3个线程在等待
    全部线程到达A集合点
    全部线程到达A集合点
    全部线程到达A集合点
    pool-1-thread-1已经到达集合点B,正在等待。目前已有1个线程在等待
    pool-1-thread-3已经到达集合点B,正在等待。目前已有2个线程在等待
    pool-1-thread-2已经到达集合点B,正在等待。目前已有3个线程在等待
    全部线程到达B集合点
    全部线程到达B集合点
    全部线程到达B集合点
    

    构造函数

    函数具名如下:

    public CountDownLatch(int count)
    

    用八个加以的数值初步化CountDownLatch,之后计数器就从那么些值初叶倒计数,直到计数值达到零。

    一种是跳远类型,来了就向来竞技,等选手比试完后就通晓结果了。跳远和CountDownLatch

    先从CountDownLatch的构造方法看起:

    四、CountDownLatch 和 CyclicBarrier 的区别

    诚如情状下对于五个可怜相似的类,我们一般都会想当然地去把她们开展类比。对于 CountDownLatch 和 CyclicBarrier 三个类,大家能够观望CountDownLatch 类都是多少个近乎于集合点的概念,非常多少个线程做完事情今后等待别的线程完结,全体线程完结之后再苏醒运转。分歧的是CountDownLatch 类必要你和睦调用 countDown() 方法缩短一个计数,然后调用 await() 方法就能够。而 CyclicBarrier 则直接调用 await() 方法就可以。

    之所以从地方来看,CountDownLatch 更偏侧于四个线程合营的景况,等你具有东西都绸缪好了,作者那边就机关实行了。而 CyclicBarrier 则是大家都在三个地点等您,大家到齐了,大家再同台施行。

    参照他事他说加以考察资料: 

    await函数

    await函数用两种格局,签字分别如下:

    public void await() throws InterruptedException
    public boolean await(long timeout, TimeUnit unit)
    

    那多少个函数的作用都以让线程阻塞等待其他线程,直到CountDownLatch的计数值变为0才继续施行之后的操作。不同在于第贰个函数未有等待时间限定,能够等到地老天荒,天荒地老,第三个函数给定三个等候超时时间,超过该时间就直接抛弃了,并且第二个函数具备重回值,超时时间之内CountDownLatch的值达到0就回来true,等待时间结束计数值都还没达到0就回来false。那四个操作在等待历程中只要等待的线程被搁浅,则会抛出InterruptedException极度。

    跳远比赛和CountDownLatch有不期而同之妙。评判员首先决定好了稍稍个党插足比赛,每种运动员直接跳远,评判员要等全体人跳完才可以操纵战表。

    public CountDownLatch(int count)
    

    countDown函数

    本条函数用来将CountDownLatch的计数值减一,函数具名如下:

    public void countDown()
    

    亟待表明的是,如若调用这么些函数的时候CountDownLatch的计数值已经为0,那么这几个函数什么也不会做。

    下边大家用代码达成一下

    协会方法会传入四个整型数N,之后调用CountDownLatch的countDown方法会对N减一,知道N减到0的时候,当前调用await措施的线程继续试行。

    getCount函数

    该函数用来获得当前CountDownLatch的计数值,函数具名如下:

    public void countDown()
    

    信誉买球网站 3

    CountDownLatch的主意不是相当的多,将它们八个个列举出来:

    模拟实验

    理论知识讲完了,须要真枪实战场来演示一下以此类的效应,大家就以下边这几个场所为例子,用CountDownLatch来促成那个须求:

    有5个选手赛跑,开跑此前,评判必要等待5个运动员都策动好能力一声令下,况且5个选手准备好之后也都亟待等待宣判发令能力开跑。

    第一剖判一下依赖关系:

    宣判发令 -> 5个运动员都希图好;
    5个运动员开跑 -> 裁判发令。

    好,信赖关系一度出去了,代码完结:

    package com.winwill.test;
    
    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    
    /**
     * @author qifuguang
     * @date 15/8/24 23:35
     */
    public class TestCountDownLatch {
        private static final int RUNNER_NUMBER = 5; // 运动员个数
        private static final Random RANDOM = new Random();
    
        public static void main(String[] args) {
            // 用于判断发令之前运动员是否已经完全进入准备状态,需要等待5个运动员,所以参数为5
            CountDownLatch readyLatch = new CountDownLatch(RUNNER_NUMBER);
            // 用于判断裁判是否已经发令,只需要等待一个裁判,所以参数为1
            CountDownLatch startLatch = new CountDownLatch(1);
            for (int i = 0; i < RUNNER_NUMBER; i  ) {
                Thread t = new Thread(new Runner((i   1)   "号运动员", readyLatch, startLatch));
                t.start();
            }
            try {
                readyLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            startLatch.countDown();
            System.out.println("裁判:所有运动员准备完毕,开始...");
        }
    
        static class Runner implements Runnable {
            private CountDownLatch readyLatch;
            private CountDownLatch startLatch;
            private String name;
    
            public Runner(String name, CountDownLatch readyLatch, CountDownLatch startLatch) {
                this.name = name;
                this.readyLatch = readyLatch;
                this.startLatch = startLatch;
            }
    
            public void run() {
                int readyTime = RANDOM.nextInt(1000);
                System.out.println(name   ":我需要"   readyTime   "秒时间准备.");
                try {
                    Thread.sleep(readyTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(name   ":我已经准备完毕.");
                readyLatch.countDown();
                try {
                    startLatch.await();  // 等待裁判发开始命令
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(name   ":开跑...");
            }
        }
    }
    

    运营结果如下:

    1号运动员:笔者索要389秒时间希图.
    2号运动员:小编索要449秒时间计划.
    3号选手:小编必要160秒时间策动.
    4号选手:作者要求325秒时间准备.
    5号运动员:小编急需978秒时间计划.
    3号选手:我已经计划完成.
    4号选手:笔者早就希图完成.
    1号运动员:小编已经策画实现.
    2号运动员:笔者早就筹划完成.
    5号选手:小编已经筹算完结.
    宣判:全体选手打算停止,开首...
    1号选手:开跑...
    5号选手:开跑...
    2号选手:开跑...
    4号选手:开跑...
    3号选手:开跑...

    能够看到,一切都以如此地健全,运动员图谋好了后来评判才发令,评判发令之后运动员才开跑。

    跑步和CyclicBarrier

    1. await() throws InterruptedException:调用该情势的线程等到构造方法传入的N减到0的时候,技巧一而再往下实行;
    2. await(long timeout, TimeUnit unit):与地方的await方法效果雷同,只可是这里有了时光限制,调用该措施的线程等到钦点的timeout时间后,不管N是或不是减至为0,都会继续往下实施;
    3. countDown():使CountDownLatch初始值N减1;
    4. long getCount():获取当前CountDownLatch维护的值;

    CyclicBarrier类

    CyclicBarrier翻译过来正是:循环的屏障。什么是循环?能够重新利用呗,对这一个类就是三个足以重复使用的屏障类。CyclicBarrier首要用来一组固定大小的线程之间,各种线程之间互相等待,当全部线程都成功某项职分之后,能力施行之后的天职。
    一般来说场景:

    有若干个线程都要求向五个数据库写多少,不过必须要具备的线程都讲数量写入完成他们手艺接二连三做之后的政工。

    解析一下以此场景的天性:

    • 依次线程都必须完毕某项任务(写多少)技能承继做持续的任务;
    • 逐个线程须要彼此等待,不能够明哲保身。

    这种情景便得以选用CyclicBarrier来宏观化解。

    抚今追昔一下原先协会跑步比赛的时候,三个评判召集5个运动员,且必需等到5个选手凑齐后本领较量打响发令枪,并且5个运动员也不能不互相等对方策画好后才起来竞技。何况该判决是能够循环的。等那批人跑起来后又足以起来重新企图别的5个选手

    上边用几个切实可行的事例来注明CountDownLatch的现实性用法:

    常用函数

    本节介绍CyclicBarrier的基本操作函数。

    上面我们看一下代码的落到实处

    public class CountDownLatchDemo {private static CountDownLatch startSignal = new CountDownLatch;//用来表示裁判员需要维护的是6个运动员private static CountDownLatch endSignal = new CountDownLatch;public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool; for (int i = 0; i < 6; i  ) { executorService.execute -> { try { System.out.println(Thread.currentThread().getName()   " 运动员等待裁判员响哨!!!"); startSignal.await(); System.out.println(Thread.currentThread().getName()   "正在全力冲刺"); endSignal.countDown(); System.out.println(Thread.currentThread().getName()   " 到达终点"); } catch (InterruptedException e) { e.printStackTrace; } System.out.println("裁判员发号施令啦!!!"); startSignal.countDown(); endSignal.await(); System.out.println("所有运动员到达终点,比赛结束!"); executorService.shutdown();}}输出结果:pool-1-thread-2 运动员等待裁判员响哨!!!pool-1-thread-3 运动员等待裁判员响哨!!!pool-1-thread-1 运动员等待裁判员响哨!!!pool-1-thread-4 运动员等待裁判员响哨!!!pool-1-thread-5 运动员等待裁判员响哨!!!pool-1-thread-6 运动员等待裁判员响哨!!!裁判员发号施令啦!!!pool-1-thread-2正在全力冲刺pool-1-thread-2 到达终点pool-1-thread-3正在全力冲刺pool-1-thread-3 到达终点pool-1-thread-1正在全力冲刺pool-1-thread-1 到达终点pool-1-thread-4正在全力冲刺pool-1-thread-4 到达终点pool-1-thread-5正在全力冲刺pool-1-thread-5 到达终点pool-1-thread-6正在全力冲刺pool-1-thread-6 到达终点所有运动员到达终点,比赛结束!
    

    构造函数

    有两种类型的构造函数,函数签名分别如下:

    public CyclicBarrier(int parties, Runnable barrierAction)
    public CyclicBarrier(int parties)
    

    参数parties表示一共有多少线程参与本次“活动”,参数barrierAction是可选的,用来钦赐当有着线程都成功这么些必得的“神秘任务”之后要求干的事情,所以barrierAction这里的动作在三个互为等待的循环内只会实行三遍。

    信誉买球网站 4

    该示例代码中设置了七个CountDownLatch,第贰个endSignal用以调节让main线程必得等到任何线程让CountDownLatch维护的数值N减到0截止。另一个startSignal用来让main线程对其余线程举办“发号施令”,startSignal援引的CountDownLatch初步值为1,而别的线程实行的run方法中都会先经过 startSignal.await()让这一个线程都被堵塞,直到main线程通过调用startSignal.countDown();,将值N减1,CountDownLatch维护的数值N为0后,其余线程本事往下实行,况兼,各个线程实行的run方法中都会透过endSignal.countDown();endSignal护卫的数值进行减一,由于往线程池提交了6个职务,会被减6次,所以endSignal爱慕的值最后会变为0,因而main线程在latch.await();闭塞结束,技巧一连往下试行。

    getParties函数

    getParties用来博取当前的CyclicBarrier一共有多少线程参数与,函数具名如下:

    public int getParties()
    

    回到到场“活动”的线程个数。

    信誉买球网站 5

    其余,要求小心的是,当调用CountDownLatch的countDown方法时,当前线程是不会被卡住,会持续往下进行,例如在该例中会继续输出pool-1-thread-4 到达终点

    await函数

    await函数用来实施等待操作,有两体系型的函数具名:

    public int await() throws InterruptedException, BrokenBarrierException
    public int await(long timeout, TimeUnit unit)
            throws InterruptedException,
                   BrokenBarrierException,
                   TimeoutException 
    

    率先个函数是二个无参函数,第一个函数能够内定等待的晚点时间。它们的成效是:平昔等待知道全体加入“活动”的线程都调用过await函数,纵然当前线程不是将要调用await函数的的末梢三个线程,当前线程将会被挂起,直到下列某一种情景发生:

    • 终极贰个线程调用了await函数;
    • 某些线程打断了近日线程;
    • 有些线程打断了别样某些正在等待的线程;
    • 其他某些线程等待时间超越给定的晚点时间;
    • 另外有些线程调用了reset函数。

    假定等待历程中线程被打断了,则会抛出InterruptedException异常;
    比如等待历程中冒出下列情况中的某一种景况,则会抛出BrokenBarrierException卓殊:

    • 任何线程被打断了;
    • 当前线程等待超时了;
    • 当前CyclicBarrier被reset了;
    • 伺机历程中CyclicBarrier损坏了;
    • 构造函数中钦定的barrierAction在实施过程中发出了特别。

    假若等待时间超越给定的最大等待时间,则会抛出TimeoutException非常,并且那个时候任何已经嗲用过await函数的线程将会继续接二连三的动作。

    重返值:重临当前线程在调用过await函数的所以线程中的编号,编号为parties-1的代表第两个调用await函数,编号为0表示是最终二个调用await函数。

    CyclicBarrier也是一种八线程并发调整的实用工具,和CountDownLatch相同享有等待计数的效果与利益,然则比较于CountDownLatch成效更抓牢大。

    isBroken函数

    给函数用来剖断barrier是还是不是曾经毁损,函数具名如下:

    public boolean isBroken()
    

    一旦因为任何原因被毁坏再次回到true,不然再次来到false

    为了精通CyclicBarrier,这里举一个浅显的事例。开运动会时,会有跑步这一项运动,大家来效仿下运动员登台时的场馆,尽管有6条跑道,在比赛起先时,就要求6个运动员在比赛初叶的时候都站在起源了,评判员吹哨后才干起首跑步。跑道起源就也就是“barrier”,是临界点,而这6个选手就类比成线程的话,正是那6个线程都必得到达钦点点了,意味着凑齐了一波,然后本事继续实践,不然每一种线程都得死死的等待,直至凑齐一波就能够。cyclic是循环的情趣,也等于说Cyclic巴里r当多少个线程凑齐了一波之后,如故有效,能够持续凑齐下一波。CyclicBarrier的执行暗中表示图如下:

    reset函数

    看名就会猜到其意义,那个函数用来重新载入参数barrier,函数签字如下:

    public void reset()
    

    例如调用了该函数,则在等待的线程将会抛出BrokenBarrierException分外。

    信誉买球网站 6CyclicBarrier实行暗意图.jpg

    getNumberWaiting函数

    该函数用来博取当前正值班守护候该barrier的线程数,函数具名如下:

    public int getNumberWaiting()
    

    当八个线程都实现了指确定地点后,工夫继续往下继续施行。那就有一点像报数的认为,要是6个线程就一定于6个选手,到赛道源点时会报数进行总括,如若刚好是6的话,这一波就凑齐了,技术往下进行。Cyclic巴里r在选拔二次后,上面依旧有效,能够持续作为计数器使用,那是与CountDownLatch的区别之一。此间的6个线程,也正是计数器的始发值6,是经过CyclicBarrier的构造方法传入的。

    模拟实验

    下边用代码完结上边包车型大巴光景:

    有5个线程都亟需向一个数据库写多少,但是必须求持有的线程都讲数量写入完成他们手艺持续做之后的专门的学问。

    上面来看下CyclicBarrier的基本点格局:

    相似境况

    代码:

    package com.winwill.test;
    
    import java.util.Random;
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * @author qifuguang
     * @date 15/8/25 00:34
     */
    public class TestCyclicBarrier {
        private static final int THREAD_NUMBER = 5;
        private static final Random RANDOM = new Random();
    
        public static void main(String[] args) {
            CyclicBarrier barrier = new CyclicBarrier(THREAD_NUMBER, new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getId()   ":我宣布,所有小伙伴写入数据完毕");
                }
            });
            for (int i = 0; i < THREAD_NUMBER; i  ) {
                Thread t = new Thread(new Worker(barrier));
                t.start();
            }
        }
    
        static class Worker implements Runnable {
            private CyclicBarrier barrier;
    
            public Worker(CyclicBarrier barrier) {
                this.barrier = barrier;
            }
    
            public void run() {
                int time = RANDOM.nextInt(1000);
                System.out.println(Thread.currentThread().getId()   ":我需要"   time   "毫秒时间写入数据.");
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":写入数据完毕,等待其他小伙伴...");
                try {
                    barrier.await(); // 等待所有线程都调用过此函数才能进行后续动作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":所有线程都写入数据完毕,继续干活...");
            }
        }
    }
    

    运作结果如下:

    10:作者急需16皮秒时间写入数据.
    11:作者索要353纳秒时间写入数据.
    12:作者索要101纳秒时间写入数据.
    13:小编需要744皮秒时间写入数据.
    14:小编必要51纳秒时间写入数据.
    10:写入数据截至,等待其余年轻人伴...
    14:写入数据停止,等待其余年轻人伴...
    12:写入数据截至,等待别的年轻人伴...
    11:写入数据结束,等待别的年轻人伴...
    13:写入数据停止,等待其余年轻人伴...
    13:小编颁发,全部同伙写入数据甘休
    13:全数线程都写入数据停止,继续干活...
    10:全部线程都写入数据结束,继续干活...
    12:全部线程都写入数据结束,继续干活...
    14:全数线程都写入数据停止,继续干活...
    11:全体线程都写入数据截至,继续干活...

    能够看看,线程小朋侪们充足团结,写完本身的数量之后都在等候其余小同伙,全体伙伴都完毕以往才继续一而再的动作。

    //等到所有的线程都到达指定的临界点await() throws InterruptedException, BrokenBarrierException //与上面的await方法功能基本一致,只不过这里有超时限制,阻塞等待直至到达超时时间为止await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException //获取当前有多少个线程阻塞等待在临界点上int getNumberWaiting()//用于查询阻塞等待的线程是否被中断boolean isBroken() //将屏障重置为初始状态。如果当前有线程正在临界点等待的话,将抛出BrokenBarrierException。void reset()
    

    重复使用

    地方的例子并不曾反映CyclicBarrier能够循环使用的特征,所以有如下代码:

    package com.winwill.test;
    
    import java.util.Random;
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * @author qifuguang
     * @date 15/8/25 00:34
     */
    public class TestCyclicBarrier {
        private static final int THREAD_NUMBER = 5;
        private static final Random RANDOM = new Random();
    
        public static void main(String[] args) throws Exception {
            CyclicBarrier barrier = new CyclicBarrier(THREAD_NUMBER, new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getId()   ":我宣布,所有小伙伴写入数据完毕");
                }
            });
            for (int i = 0; i < THREAD_NUMBER; i  ) {
                Thread t = new Thread(new Worker(barrier));
                t.start();
            }
            Thread.sleep(10000);
            System.out.println("================barrier重用==========================");
            for (int i = 0; i < THREAD_NUMBER; i  ) {
                Thread t = new Thread(new Worker(barrier));
                t.start();
            }
        }
    
        static class Worker implements Runnable {
            private CyclicBarrier barrier;
    
            public Worker(CyclicBarrier barrier) {
                this.barrier = barrier;
            }
    
            public void run() {
                int time = RANDOM.nextInt(1000);
                System.out.println(Thread.currentThread().getId()   ":我需要"   time   "毫秒时间写入数据.");
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":写入数据完毕,等待其他小伙伴...");
                try {
                    barrier.await(); // 等待所有线程都调用过此函数才能进行后续动作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":所有线程都写入数据完毕,继续干活...");
            }
        }
    }
    

    运作结果:

    10:小编索要228微秒时间写入数据.
    11:作者须求312阿秒时间写入数据.
    12:作者需求521飞秒时间写入数据.
    13:小编急需720皮秒时间写入数据.
    14:小编急需377飞秒时间写入数据.
    10:写入数据截至,等待别的年轻人伴...
    11:写入数据结束,等待其余年轻人伴...
    14:写入数据停止,等待别的年轻人伴...
    12:写入数据甘休,等待别的年轻人伴...
    13:写入数据甘休,等待其余年轻人伴...
    13:作者发布,全数同伙写入数据甘休
    13:全数线程都写入数据截至,继续干活...
    10:全体线程都写入数据甘休,继续干活...
    11:全数线程都写入数据停止,继续干活...
    14:全部线程都写入数据截止,继续干活...
    12:全数线程都写入数据停止,继续干活...
    ================barrier重用==========================
    15:笔者必要212纳秒时间写入数据.
    16:作者需求691纳秒时间写入数据.
    17:小编急需530阿秒时间写入数据.
    18:笔者急需758微秒时间写入数据.
    19:小编索要604飞秒时间写入数据.
    15:写入数据截止,等待别的年轻人伴...
    17:写入数据结束,等待别的年轻人伴...
    19:写入数据结束,等待其余年轻人伴...
    16:写入数据截至,等待别的年轻人伴...
    18:写入数据截至,等待别的年轻人伴...
    18:作者公布,全部友人写入数据甘休
    18:全体线程都写入数据截止,继续干活...
    15:全体线程都写入数据停止,继续干活...
    19:全部线程都写入数据停止,继续干活...
    16:全数线程都写入数据结束,继续干活...
    17:全部线程都写入数据截至,继续干活...

    能够看到,barrier的确是援引了。

    除此以外部须要要专心的是,CyclicBarrier提供了那般的构造方法:

    等候超时

    借使await的时候设置了八个最长等待时间,何况等待超时,则会怎么样呢?上边包车型地铁例证故意让三个线程延迟一段时间才起来写多少,那样就能够现出先等待的线程等待最后一个线程抛出等待超时万分的场合。

    package com.winwill.test;
    
    import java.util.Random;
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    /**
     * @author qifuguang
     * @date 15/8/25 00:34
     */
    public class TestCyclicBarrier {
        private static final int THREAD_NUMBER = 5;
        private static final Random RANDOM = new Random();
    
        public static void main(String[] args) throws Exception {
            CyclicBarrier barrier = new CyclicBarrier(THREAD_NUMBER, new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getId()   ":我宣布,所有小伙伴写入数据完毕");
                }
            });
            for (int i = 0; i < THREAD_NUMBER; i  ) {
                if (i < THREAD_NUMBER - 1) {
                    Thread t = new Thread(new Worker(barrier));
                    t.start();
                } else {  //最后一个线程故意延迟3s创建。
                    Thread.sleep(3000);
                    Thread t = new Thread(new Worker(barrier));
                    t.start();
                }
            }
        }
    
        static class Worker implements Runnable {
            private CyclicBarrier barrier;
    
            public Worker(CyclicBarrier barrier) {
                this.barrier = barrier;
            }
    
            public void run() {
                int time = RANDOM.nextInt(1000);
                System.out.println(Thread.currentThread().getId()   ":我需要"   time   "毫秒时间写入数据.");
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":写入数据完毕,等待其他小伙伴...");
                try {
                    barrier.await(2000, TimeUnit.MILLISECONDS); // 只等待2s,必然会等待最后一个线程超时
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()   ":所有线程都写入数据完毕,继续干活...");
            }
        }
    }
    

    运转结果:

    10:作者须要820飞秒时间写入数据.
    11:小编供给140纳秒时间写入数据.
    12:我须求640皮秒时间写入数据.
    13:作者急需460阿秒时间写入数据.
    11:写入数据停止,等待别的年轻人伴...
    13:写入数据结束,等待别的年轻人伴...
    12:写入数据停止,等待别的年轻人伴...
    10:写入数据停止,等待别的年轻人伴...
    java.util.concurrent.BrokenBarrierException
    12:全数线程都写入数据甘休,继续干活...
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    13:所无线程都写入数据结束,继续干活...
    11:全体线程都写入数据截至,继续干活...
    10:全体线程都写入数据截至,继续干活...
    at com.winwill.test.TestCyclicBarrier$Worker.run(TestCyclicBarrier.java:52)
    at java.lang.Thread.run(Thread.java:744)
    java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.winwill.test.TestCyclicBarrier$Worker.run(TestCyclicBarrier.java:52)
    at java.lang.Thread.run(Thread.java:744)
    java.util.concurrent.TimeoutException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.winwill.test.TestCyclicBarrier$Worker.run(TestCyclicBarrier.java:52)
    at java.lang.Thread.run(Thread.java:744)
    java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.winwill.test.TestCyclicBarrier$Worker.run(TestCyclicBarrier.java:52)
    at java.lang.Thread.run(Thread.java:744)
    14:作者索要850阿秒时间写入数据.
    java.util.concurrent.BrokenBarrierException
    14:写入数据停止,等待其余年轻人伴...
    14:全体线程都写入数据截至,继续干活...
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.winwill.test.TestCyclicBarrier$Worker.run(TestCyclicBarrier.java:52)
    at java.lang.Thread.run(Thread.java:744)

    能够看来,前边八个线程等待最后二个线程超时了,这年他俩不再等待最终这么些小同伴了,而是抛出万分并都承继持续的动作。最终这些线程屁颠屁颠地完毕写入数据操作之后也继续了承袭的动作。须要证实的是,产生了晚点十分时候,还不曾马到成功“神秘职分”的线程在成就职责之后不会做别的等待,而是会直接实施后续的操作。

    public CyclicBarrier(int parties, Runnable barrierAction)
    

    总结

    CountDownLatch和Cyclic巴里r都能够达成线程之间的等候,只可是它们主导差别:

    • CountDownLatch一般用于某个线程A等待若干个其余线程实施完职责之后,它才施行;
    • CyclicBarrier一般用于一组线程相互等待至某些状态,然后这一组线程再同时进行;
    • CountDownLatch是不可知重用的,而CyclicBarrier是足以选择的。

    能够用来,当钦命的线程都达到了钦定的临界点的时,接下去实践的操作能够由barrierAction传入就能够。

    声明

    正文为小编原创,也断然个人见解,如领悟有误,请留言相告。转载请评释出处: http://qifuguang.me/2016/08/25/[Java并发包学习五]CountDownLatch和CyclicBarrier介绍
    假定你高兴自身的稿子,请关怀自个儿的微信订阅号:“机智的技师”,越来越多美貌,尽在里头:

    信誉买球网站 7

    一个事例

    下边用三个简易的事例,来看下CyclicBarrier的用法,我们来效仿下方面包车型地铁选手的例子。

    public class CyclicBarrierDemo { //指定必须有6个运动员到达才行 private static CyclicBarrier barrier = new CyclicBarrier -> { System.out.println("所有运动员入场,裁判员一声令下!!!!!"); }); public static void main(String[] args) { System.out.println("运动员准备进场,全场欢呼............"); ExecutorService service = Executors.newFixedThreadPool; for (int i = 0; i < 6; i  ) { service.execute -> { try { System.out.println(Thread.currentThread().getName()   " 运动员,进场"); barrier.await(); System.out.println(Thread.currentThread().getName()   " 运动员出发"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace; } }}输出结果:运动员准备进场,全场欢呼............pool-1-thread-2 运动员,进场pool-1-thread-1 运动员,进场pool-1-thread-3 运动员,进场pool-1-thread-4 运动员,进场pool-1-thread-5 运动员,进场pool-1-thread-6 运动员,进场所有运动员入场,裁判员一声令下!!!!!pool-1-thread-6 运动员出发pool-1-thread-1 运动员出发pool-1-thread-5 运动员出发pool-1-thread-4 运动员出发pool-1-thread-3 运动员出发pool-1-thread-2 运动员出发
    

    从出口结果能够见见,当6个运动员都到达了内定的临界点时候,技术持续往下推行,否则,则会堵塞等待在调用await()

    CountDownLatch与CyclicBarrier都以用以调整并发的工具类,都能够知晓成维护的正是一个计数器,不过那二者依旧各有差异侧重视的:

    1. CountDownLatch一般用于有些线程A等待若干个其余线程实行完任务之后,它才实践;而CyclicBarrier一般用于一组线程相互等待至某些状态,然后这一组线程再同一时间实践;CountDownLatch重申一个线程等多少个线程达成某事情。CyclicBarrier是多个线程互等,等豪门都成功,再牵手共进。
    2. 调用CountDownLatch的countDown方法后,当前线程并不会阻塞,会持续往下施行;而调用CyclicBarrier的await方法,会卡住当前线程,直到CyclicBarrier钦定的线程全体都到达了钦定点的时候,能力三番五次往下进行;
    3. CountDownLatch方法比较少,操作相比轻松,而Cyclic巴里r提供的法门更加多,举个例子能够通过getNumberWaiting(),isBroken()那些方式获得当前多个线程的图景,与此同临时常候Cyclic巴里r的构造方法能够流传barrierAction,钦赐当有着线程都达到时推行的事体功用;
    4. CountDownLatch是不可能复用的,而CyclicLatch是可以复用的。

    本文由买球网站发布于篮球相关,转载请注明出处:信誉买球网站:大白话说java并发工具类,Java并发

    关键词: 信誉买球网站 正规买球网站