【JUC的四大同步辅助类】

发布时间:2024年01月03日


提示:以下是本篇文章正文内容,下面案例可供参考

一、CountDownLatch

CountDownLatch如同火箭发射,计数只能不断减减,当到达0时即发射
场景示例:考场中有多个同学考试,每个同学写完试卷后,将试卷交给老师即可离开,老师需要收齐所有人的试卷后才能离开。

代码如下(示例)

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // CountDownLatch 倒计时到0,发射(减法)

        // 考场学生人数为 6(一旦定下就不能在增加)
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    // 模拟每个学生完成试卷的时间不同(线程休眠随机时间)
                    Thread.sleep(new Random().nextInt(3000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t同学写完,离开教室");
                // 上交试卷给老师(走一个,计数减少一个)
                countDownLatch.countDown();
            }, i + "号考生").start();
        }

        // 主线程相当于老师,需要等所有的人交卷,才能离开(阻塞当前线程,等待所有线程完成任务,即 countDown)
        countDownLatch.await();

        Thread.currentThread().setName("老师");
        System.out.println(Thread.currentThread().getName() + "\t收齐试卷,关门走人");
    }
}

输出结果

在这里插入图片描述


二、CyclicBarrier

CyclicBarrier如同游戏匹配,不凑齐人数,就一直在匹配界面,达到指定人数后才能开始对战

代码如下(示例)

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // CyclicBarrier 指定值达到 0,发射

        // 需要十个人才能开始游戏,(指定个数,之后不能改变,满足条件后,自动执行 Runnable 方法)
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {
            System.out.println("十个人已经全部确认,开始游戏");
        });

        for (int i = 1; i <= 10; i++) {
            final int tmpInt = i;
            new Thread(() -> {
                try {
                    // 模拟玩家匹配时间
                    Thread.sleep(new Random().nextInt(3000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t已经确认");
                try {
                    // 等待其他玩家准备(阻塞等待,等待人数减 1,减到 0,就发车)
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, tmpInt + "号玩家").start();
        }

    }
}

输出结果
在这里插入图片描述


三、Semaphore

Semaphore如同一个停车场,里面的车位数是固定的,当停满车后,必须有车出来才能再进

Semaphore 主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。
涉及到并发就有有两种模式:

  1. 非公平(谁抢到是谁的),默认是非公平的
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
  1. 公平(先来后到),当 fair 为 true 是公平的
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

代码如下(示例)

public class Test {
    public static void main(String[] args) throws InterruptedException {
        // 一共 3 个停车位(资源数开始时固定)
        Semaphore semaphore = new Semaphore(3);// 默认非公平(抢占式)

        // 模拟 6 辆汽车要停车
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    // 询问还有没有停车位,有就进去,没有等待(获得资源)
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t抢到车位");
                    // 模拟停车时间
                    Thread.sleep(new Random().nextInt(3000));
                    System.out.println(Thread.currentThread().getName() + "\t事情办完,离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 办完事情,开车离开(释放资源)
                    semaphore.release();
                }
            }, i + "号车主").start();
        }
    }
}

输出结果
在这里插入图片描述


四、Phaser

Phaser是JDK 7新增的一个同步辅助类,它可以实现CyclicBarrier和CountDownLatch类似的功能,而且它支持对任务的动态调整,并支持分层结构来达到更高的吞吐量。

CountDownLatch 和 CyclicBarrier 在最初就固定了线程的数量,而且中途不可改变,当完成指定的任务后,就不能再次使用,Phaser 就解决了该问题。

class player implements Runnable {

    private final Phaser phaser;

    player(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        try {
            // 第一阶段——确定参赛的运动员人数(等待创建好所有线程再开始)
            phaser.arriveAndAwaitAdvance();

            // 第二阶段——等待所有选手都做好准备,发令枪再开始
            Thread.sleep(new Random().nextInt(3000));// 模拟热身准备
            System.out.println(Thread.currentThread().getName() + "号运动员准备完毕");
            phaser.arriveAndAwaitAdvance();

            // 第三阶段——所有运动员开始跑步
            Thread.sleep(new Random().nextInt(3000));// 模拟跑步时间
            System.out.println(Thread.currentThread().getName() + "号运动员冲线!");

            // 冲线后结束(线程下线注销)
            phaser.arriveAndDeregister();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException {

        // 模拟了 100 米赛跑,10 名运动员,只等裁判一声令下。当所有人都到达终点时,比赛结束。
        // 设置初始的注册人数(1 个裁判)
        final Phaser phaser = new Phaser(1);
        // 十名运动员
        for (int index = 0; index < 10; index++) {
            // 每个运动员都注册到其中,即确定参加比赛(动态增加,复用)
            phaser.register();
            new Thread(new player(phaser), index + "号运动员").start();
        }
        System.out.println("比赛开始");
        // 裁判下线,注销当前线程,比赛开始
        phaser.arriveAndDeregister();
        // 所有运动员是否到达终点,没有就一直等待
        while (!phaser.isTerminated()) {
        }
        System.out.println("所有运动员到达终点,比赛结束");

    }
}

输出结果
在这里插入图片描述

文章来源:https://blog.csdn.net/m0_69269392/article/details/135368448
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。