多线程与高并发之CyclicBarrier

多线程与高并发之CyclicBarrier

​ CyclicBarrier主要用于实现,当某一个线程需要等待其他多个线程执行完某些操作之后才开始执行。CyclicBarrier初始化了一个基数的数量,然后各个线程执行完某些操作之后,调用await方法进入等待状态,当等待的进程数量等于初始化的数量的时候,所有的线程将重新激活继续执行。CycliBarrier就跟名字一样他就是各个线程的障碍,只有全部线程到齐之后才能跨过这个障碍。

需求背景

10个运动员,不同时间到体育场比赛,所有运动员到了之后就开始比赛,最后模拟各个赛道的运动员的最终成绩

实现设计

  1. 创建一个运动员类(Sportsman)有姓名、赛道、CyclicBarrier对象等几个属性

  2. 运动员线程都是先到达体育场,进行热身。所有运动员到了之后开始鸣枪开始

  3. 最后统计各个赛道运动员的成绩

代码实现

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    public static void main(String[] args) {
        //假设有8个赛道
        String[] sportmans = {"博尔特", "鲍威尔", "加特林", "盖伊", "布雷克", "格林", "波尔顿", "罗杰斯"};
        //1.定义cyclicBarrier对象,定义有几个参与者,同时可以使用第二参数来输出输出是否全部运动元已经到场
        CyclicBarrier cyclicBarrier = new CyclicBarrier(8, new Runnable() {
            @Override
            public void run() {
                System.out.println("8位运动员都已经全部到场,比赛开始......");
            }
        });
        for (int i = 1; i <= 8; i++) {
            //初始化运动员对象,请启动线程
            new Thread(new Sportsman(sportmans[i - 1], i + "", cyclicBarrier)).start();
        }

    }

}

class Sportsman implements Runnable {

    /**
     * 姓名
     */
    String name;
    /**
     * 跑道
     */
    String track;

    //计数器屏障对象,所有运动员到场之后才能开始鸣枪
    CyclicBarrier cyclicBarrier;

    public Sportsman(String name, String track, CyclicBarrier cyclicBarrier) {
        this.name = name;
        this.track = track;
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        System.out.println("第【" + this.track + "】赛道的【" + this.name + "】已经到场,正在热身");
        try {
            //等待其他到场准备
            cyclicBarrier.await();
            //模拟运动员100的时间,全部运动员都是高手,所有这边模式成绩都是在9-10秒之间
            double time = Math.random();
            time = 9 + time;
            BigDecimal bg = new BigDecimal(time).setScale(2, RoundingMode.HALF_DOWN);
            Thread.sleep(bg.multiply(new BigDecimal(1000)).intValue());
            System.out.println("第【" + this.track + "】赛道的【" + this.name + "】完成比赛,比赛时间:" + bg.toString() + "s");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }
}

代码的执行效果如下:

第【1】赛道的【博尔特】已经到场,正在热身
第【5】赛道的【布雷克】已经到场,正在热身
第【3】赛道的【加特林】已经到场,正在热身
第【4】赛道的【盖伊】已经到场,正在热身
第【2】赛道的【鲍威尔】已经到场,正在热身
第【7】赛道的【波尔顿】已经到场,正在热身
第【6】赛道的【格林】已经到场,正在热身
第【8】赛道的【罗杰斯】已经到场,正在热身
8位运动员都已经全部到场,比赛开始......
第【1】赛道的【博尔特】完成比赛,比赛时间:9.03s
第【2】赛道的【鲍威尔】完成比赛,比赛时间:9.05s
第【7】赛道的【波尔顿】完成比赛,比赛时间:9.12s
第【8】赛道的【罗杰斯】完成比赛,比赛时间:9.19s
第【4】赛道的【盖伊】完成比赛,比赛时间:9.24s
第【6】赛道的【格林】完成比赛,比赛时间:9.40s
第【5】赛道的【布雷克】完成比赛,比赛时间:9.81s
第【3】赛道的【加特林】完成比赛,比赛时间:9.86s

扩展需求

如果这个时候我们需要得到最后所有运动员的排名以及对应的成绩,我们如何实现?

这个时候我们可以结合countdownlatch计数器来实现,在每个运动员对象中新增一个CountDownLatch对象,同时新增裁判对象,用于记录所有运动员所有成绩,并在比赛结束的时候公布最后结果.

修改后第代码

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class CyclicBarrierTest {
    public static void main(String[] args) throws Exception {
        //假设有8个赛道
        String[] sportmanNames = {"博尔特", "鲍威尔", "加特林", "盖伊", "布雷克", "格林", "波尔顿", "罗杰斯"};
        List<Sportsman> sportsmanList = new ArrayList<Sportsman>();
        BigDecimal[] scores = new BigDecimal[8];
        //1.定义cyclicBarrier对象,定义有几个参与者,同时可以使用第二参数来输出输出是否全部运动元已经到场
        CyclicBarrier cyclicBarrier = new CyclicBarrier(8, new Runnable() {
            @Override
            public void run() {
                System.out.println("8位运动员都已经全部到场,比赛开始......");
            }
        });
        CountDownLatch countDownLatch = new CountDownLatch(8);
        for (int i = 1; i <= 8; i++) {
            //初始化运动员对象,请启动线程
            Sportsman sportsman = new Sportsman(sportmanNames[i - 1], i + "", cyclicBarrier, countDownLatch);
            new Thread(sportsman).start();
            sportsmanList.add(sportsman);
        }
        Judge judge = new Judge(countDownLatch);
        judge.sportsmanList = sportsmanList;
        new Thread(judge).start();


    }

}

class Judge implements Runnable {
    CountDownLatch countDownLatch;
    List<Sportsman> sportsmanList;

    public Judge(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("裁判就位....");
        try {
            countDownLatch.await();
            System.out.println("比赛结束,等待裁判公布最后成绩.....");
            sportsmanList = sportsmanList.stream().sorted(Comparator.comparing(Sportsman::getScore))
                    .collect(Collectors.toList());
            int i = 0;
            for (Sportsman sportsman : sportsmanList) {
                System.out.println("第【" + (i+1) + "】名-->" + "第【" + sportsmanList.get(i).track + "】赛道的【" + sportsmanList.get(i).name + "】完成比赛,比赛时间:" + sportsmanList.get(i).score + "s");
                i++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

class Sportsman implements Runnable {
    /**
     * 姓名
     */
    String name;
    /**
     * 跑道
     */
    String track;

    //计数器屏障对象,所有运动员到场之后才能开始鸣枪
    CyclicBarrier cyclicBarrier;

    CountDownLatch countDownLatch;

    BigDecimal score;

    public BigDecimal getScore() {
        return score;
    }

    public Sportsman(String name, String track, CyclicBarrier cyclicBarrier, CountDownLatch countDownLatch) {
        this.name = name;
        this.track = track;
        this.cyclicBarrier = cyclicBarrier;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("第【" + this.track + "】赛道的【" + this.name + "】已经到场,正在热身");
        try {
            //等待其他到场准备
            cyclicBarrier.await();
            //模拟运动员100的时间,全部运动员都是高手,所有这边模式成绩都是在9-10秒之间
            double time = Math.random();
            time = 9 + time;
            score = new BigDecimal(time).setScale(2, RoundingMode.HALF_DOWN);
            Thread.sleep(score.multiply(new BigDecimal(1000)).intValue());
            System.out.println("第【" + this.track + "】赛道的【" + this.name + "】完成比赛,比赛时间:" + score.toString() + "s");

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();
        }

    }

}

看看这个时候的运行结果:

裁判就位....
第【1】赛道的【博尔特】已经到场,正在热身
第【2】赛道的【鲍威尔】已经到场,正在热身
第【3】赛道的【加特林】已经到场,正在热身
第【4】赛道的【盖伊】已经到场,正在热身
第【5】赛道的【布雷克】已经到场,正在热身
第【6】赛道的【格林】已经到场,正在热身
第【7】赛道的【波尔顿】已经到场,正在热身
第【8】赛道的【罗杰斯】已经到场,正在热身
8位运动员都已经全部到场,比赛开始......
第【2】赛道的【鲍威尔】完成比赛,比赛时间:9.30s
第【5】赛道的【布雷克】完成比赛,比赛时间:9.51s
第【8】赛道的【罗杰斯】完成比赛,比赛时间:9.54s
第【7】赛道的【波尔顿】完成比赛,比赛时间:9.81s
第【6】赛道的【格林】完成比赛,比赛时间:9.83s
第【1】赛道的【博尔特】完成比赛,比赛时间:9.90s
第【3】赛道的【加特林】完成比赛,比赛时间:9.91s
第【4】赛道的【盖伊】完成比赛,比赛时间:9.93s
比赛结束,等待裁判公布最后成绩.....
第【1】名-->第【2】赛道的【鲍威尔】完成比赛,比赛时间:9.30s
第【2】名-->第【5】赛道的【布雷克】完成比赛,比赛时间:9.51s
第【3】名-->第【8】赛道的【罗杰斯】完成比赛,比赛时间:9.54s
第【4】名-->第【7】赛道的【波尔顿】完成比赛,比赛时间:9.81s
第【5】名-->第【6】赛道的【格林】完成比赛,比赛时间:9.83s
第【6】名-->第【1】赛道的【博尔特】完成比赛,比赛时间:9.90s
第【7】名-->第【3】赛道的【加特林】完成比赛,比赛时间:9.91s
第【8】名-->第【4】赛道的【盖伊】完成比赛,比赛时间:9.93s

你可能感兴趣的:(多线程与高并发)