Java闭锁(CountDownLatch)和栅栏(CyclicBarrier)

假设一场短跑比赛,使用多个线程代表每个运动员的状态和比赛过程,需要每个运动员同时出发,打印出每个关键节点的时间作为参考:

CountDownLatch

来自API文档
在这里插入图片描述

所有方法

Modifier and TypeMethod and Description
voidawait()导致当前线程等到锁存器计数到零,除非线程是 interrupted
booleanawait(long timeout, TimeUnit unit)使当前线程等待直到锁存器计数到零为止,除非线程为 interrupted或指定的等待时间过去。
voidcountDown()减少锁存器的计数,如果计数达到零,释放所有等待的线程。
longgetCount()返回当前计数。
StringtoString()返回一个标识此锁存器的字符串及其状态。
package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {
        CountDownLatch startLatch = new CountDownLatch(1);//控制比赛协作
        CountDownLatch endLatch = new CountDownLatch(8);// 每个人的比赛进程

        Runner run1 = new Runner(1,startLatch, endLatch);
        Runner run2 = new Runner(2, startLatch,endLatch);
        Runner run3 = new Runner(3, startLatch,endLatch);
        Runner run4 = new Runner(4, startLatch,endLatch);
        Runner run5 = new Runner(5, startLatch,endLatch);
        Runner run6 = new Runner(6, startLatch,endLatch);
        Runner run7 = new Runner(7, startLatch,endLatch);
        Runner run8 = new Runner(8, startLatch,endLatch);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();

        System.out.println("3秒钟预备!");
        Thread.sleep(3000);
        System.out.println("起跑!"+sdf.format(new Date()));
        startLatch.countDown(); //工作开始
        endLatch.await();// 等待所有工人完成工作
        System.out.println("比赛完成 " + sdf.format(new Date()));
    }

    static class Runner extends Thread {
        int no;
        CountDownLatch startLatch;
        CountDownLatch endLatch;
        public Runner(int no, CountDownLatch startLatch,CountDownLatch endLatch) {
            this.no = no;
            this.startLatch=startLatch;
            this.endLatch = endLatch;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                System.out.println("run "+no+"进入赛道,等待开始!预计用时:"+runTime+"ms");
                startLatch.await(); //等待开始工作时间
                System.out.println("run " + no + " 起跑时间 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("run " + no + " 到达终点时间 " + sdf.format(new Date())+";剩余完成比赛人:"+(endLatch.getCount()-1));
//                if(no == 1) {   // code1
                    endLatch.countDown();// 完成比赛,计数器减一
//                }
            }
        }
    }
}
// out
3秒钟预备!
run 5进入赛道,等待开始!预计用时:8974ms
run 1进入赛道,等待开始!预计用时:7970ms
run 8进入赛道,等待开始!预计用时:4728ms
run 7进入赛道,等待开始!预计用时:8472ms
run 4进入赛道,等待开始!预计用时:3724ms
run 2进入赛道,等待开始!预计用时:2216ms
run 3进入赛道,等待开始!预计用时:7468ms
run 6进入赛道,等待开始!预计用时:3222ms
起跑!2021-04-14 14:58:01
run 5 起跑时间 2021-04-14 14:58:01
run 1 起跑时间 2021-04-14 14:58:01
run 8 起跑时间 2021-04-14 14:58:01
run 4 起跑时间 2021-04-14 14:58:01
run 7 起跑时间 2021-04-14 14:58:01
run 3 起跑时间 2021-04-14 14:58:01
run 6 起跑时间 2021-04-14 14:58:01
run 2 起跑时间 2021-04-14 14:58:01
run 2 到达终点时间 2021-04-14 14:58:03;剩余完成比赛人:7
run 6 到达终点时间 2021-04-14 14:58:04;剩余完成比赛人:6
run 4 到达终点时间 2021-04-14 14:58:05;剩余完成比赛人:5
run 8 到达终点时间 2021-04-14 14:58:06;剩余完成比赛人:4
run 3 到达终点时间 2021-04-14 14:58:08;剩余完成比赛人:3
run 1 到达终点时间 2021-04-14 14:58:09;剩余完成比赛人:2
run 7 到达终点时间 2021-04-14 14:58:09;剩余完成比赛人:1
run 5 到达终点时间 2021-04-14 14:58:10;剩余完成比赛人:0
比赛完成 2021-04-14 14:58:10

通过上面的输入结果得到:所有人同时起步,且详细记录了比赛结束的时间;
如果放开注释code1,发现比赛无法结束,因为只有run1正式通知了裁判组完成了比赛(endLatch.countDown());

3秒钟预备!
run 7进入赛道,等待开始!预计用时:8472ms
run 8进入赛道,等待开始!预计用时:4728ms
run 5进入赛道,等待开始!预计用时:8974ms
run 4进入赛道,等待开始!预计用时:3724ms
run 2进入赛道,等待开始!预计用时:2216ms
run 6进入赛道,等待开始!预计用时:3222ms
run 1进入赛道,等待开始!预计用时:7970ms
run 3进入赛道,等待开始!预计用时:7468ms
起跑!2021-04-14 14:59:10
run 8 起跑时间 2021-04-14 14:59:10
run 5 起跑时间 2021-04-14 14:59:10
run 7 起跑时间 2021-04-14 14:59:10
run 4 起跑时间 2021-04-14 14:59:10
run 2 起跑时间 2021-04-14 14:59:10
run 3 起跑时间 2021-04-14 14:59:10
run 1 起跑时间 2021-04-14 14:59:10
run 6 起跑时间 2021-04-14 14:59:10
run 2 到达终点时间 2021-04-14 14:59:12;剩余完成比赛人:7
run 6 到达终点时间 2021-04-14 14:59:13;剩余完成比赛人:7
run 4 到达终点时间 2021-04-14 14:59:13;剩余完成比赛人:7
run 8 到达终点时间 2021-04-14 14:59:14;剩余完成比赛人:7
run 3 到达终点时间 2021-04-14 14:59:17;剩余完成比赛人:7
run 1 到达终点时间 2021-04-14 14:59:18;剩余完成比赛人:7
run 7 到达终点时间 2021-04-14 14:59:18;剩余完成比赛人:6
run 5 到达终点时间 2021-04-14 14:59:19;剩余完成比赛人:6

CyclicBarrier

在这里插入图片描述

所有方法

intawait()等待所有 parties已经在这个障碍上调用了 await
intawait(long timeout, TimeUnit unit)等待所有 parties已经在此屏障上调用 await ,或指定的等待时间过去。
intgetNumberWaiting()返回目前正在等待障碍的各方的数量。
intgetParties()返回旅行这个障碍所需的聚会数量。
booleanisBroken()查询这个障碍是否处于破碎状态。
voidreset()将屏障重置为初始状态。

CyclicBarrier有两个构造方法:

CyclicBarrier(int parties)

创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。

package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
        Runner run1 = new Runner(1, cyclicBarrier);
        Runner run2 = new Runner(2, cyclicBarrier);
        Runner run3 = new Runner(3, cyclicBarrier);
        Runner run4 = new Runner(4, cyclicBarrier);
        Runner run5 = new Runner(5, cyclicBarrier);
        Runner run6 = new Runner(6, cyclicBarrier);
        Runner run7 = new Runner(7, cyclicBarrier);
        Runner run8 = new Runner(8, cyclicBarrier);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();
    }

    static class Runner extends Thread {
        int no;
        CyclicBarrier cyclicBarrier;
        public Runner(int no, CyclicBarrier cyclicBarrier) {
            this.no = no;
            this.cyclicBarrier=cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                Thread.sleep(runTime/10);// 放大线程准备时间
                System.out.println("run "+no+"进入赛道,等待开始!预计用时:"+runTime+"ms,准备完成人数:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("run " + no + " 起跑时间 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
                System.out.println("run " + no + " 预计到达终点时间 " + sdf.format(new Date())+";完成比赛人数:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("全部完成 " + sdf.format(new Date()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

// out
run 2进入赛道,等待开始!预计用时:2216ms,准备完成人数:1
run 6进入赛道,等待开始!预计用时:3222ms,准备完成人数:2
run 4进入赛道,等待开始!预计用时:3724ms,准备完成人数:3
run 8进入赛道,等待开始!预计用时:4728ms,准备完成人数:4
run 3进入赛道,等待开始!预计用时:7468ms,准备完成人数:5
run 1进入赛道,等待开始!预计用时:7970ms,准备完成人数:6
run 7进入赛道,等待开始!预计用时:8472ms,准备完成人数:7
run 5进入赛道,等待开始!预计用时:8974ms,准备完成人数:8
run 1 起跑时间 2021-04-14 14:53:31
run 2 起跑时间 2021-04-14 14:53:31
run 4 起跑时间 2021-04-14 14:53:31
run 3 起跑时间 2021-04-14 14:53:31
run 8 起跑时间 2021-04-14 14:53:31
run 5 起跑时间 2021-04-14 14:53:31
run 7 起跑时间 2021-04-14 14:53:31
run 6 起跑时间 2021-04-14 14:53:31
run 2 预计到达终点时间 2021-04-14 14:53:33;完成比赛人数:1
run 6 预计到达终点时间 2021-04-14 14:53:34;完成比赛人数:2
run 4 预计到达终点时间 2021-04-14 14:53:34;完成比赛人数:3
run 8 预计到达终点时间 2021-04-14 14:53:35;完成比赛人数:4
run 3 预计到达终点时间 2021-04-14 14:53:38;完成比赛人数:5
run 1 预计到达终点时间 2021-04-14 14:53:39;完成比赛人数:6
run 7 预计到达终点时间 2021-04-14 14:53:39;完成比赛人数:7
run 5 预计到达终点时间 2021-04-14 14:53:40;完成比赛人数:8
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40

Process finished with exit code 0


CyclicBarrier(int parties, Runnable barrierAction)

创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。

package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(8,new Runnable(){
            @Override
            public void run() {
                System.out.println("********裁判组记录,发令***********");
                System.out.println(sdf.format(new Date()));
            }
        });
        Runner run1 = new Runner(1, cyclicBarrier);
        Runner run2 = new Runner(2, cyclicBarrier);
        Runner run3 = new Runner(3, cyclicBarrier);
        Runner run4 = new Runner(4, cyclicBarrier);
        Runner run5 = new Runner(5, cyclicBarrier);
        Runner run6 = new Runner(6, cyclicBarrier);
        Runner run7 = new Runner(7, cyclicBarrier);
        Runner run8 = new Runner(8, cyclicBarrier);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();
    }

    static class Runner extends Thread {
        int no;
        CyclicBarrier cyclicBarrier;
        public Runner(int no, CyclicBarrier cyclicBarrier) {
            this.no = no;
            this.cyclicBarrier=cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                Thread.sleep(runTime/10);// 放大线程准备时间
                System.out.println("run "+no+"进入赛道,等待开始!预计用时:"+runTime+"ms,准备完成人数:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("run " + no + " 起跑时间 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
                System.out.println("run " + no + " 预计到达终点时间 " + sdf.format(new Date())+";完成比赛人数:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("全部完成 " + sdf.format(new Date()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


//out
run 2进入赛道,等待开始!预计用时:2216ms,准备完成人数:1
run 6进入赛道,等待开始!预计用时:3222ms,准备完成人数:2
run 4进入赛道,等待开始!预计用时:3724ms,准备完成人数:3
run 8进入赛道,等待开始!预计用时:4728ms,准备完成人数:4
run 3进入赛道,等待开始!预计用时:7468ms,准备完成人数:5
run 1进入赛道,等待开始!预计用时:7970ms,准备完成人数:6
run 7进入赛道,等待开始!预计用时:8472ms,准备完成人数:7
run 5进入赛道,等待开始!预计用时:8974ms,准备完成人数:8
********裁判组记录,发令***********
2021-04-14 14:55:54
run 5 起跑时间 2021-04-14 14:55:54
run 2 起跑时间 2021-04-14 14:55:54
run 4 起跑时间 2021-04-14 14:55:54
run 3 起跑时间 2021-04-14 14:55:54
run 7 起跑时间 2021-04-14 14:55:54
run 6 起跑时间 2021-04-14 14:55:54
run 1 起跑时间 2021-04-14 14:55:54
run 8 起跑时间 2021-04-14 14:55:54
run 2 预计到达终点时间 2021-04-14 14:55:56;完成比赛人数:1
run 6 预计到达终点时间 2021-04-14 14:55:57;完成比赛人数:2
run 4 预计到达终点时间 2021-04-14 14:55:58;完成比赛人数:3
run 8 预计到达终点时间 2021-04-14 14:55:59;完成比赛人数:4
run 3 预计到达终点时间 2021-04-14 14:56:02;完成比赛人数:5
run 1 预计到达终点时间 2021-04-14 14:56:02;完成比赛人数:6
run 7 预计到达终点时间 2021-04-14 14:56:03;完成比赛人数:7
run 5 预计到达终点时间 2021-04-14 14:56:03;完成比赛人数:8
********裁判组记录,发令***********
2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03

版权声明:本文为qq_37206616原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。