05_JUC强大的辅助类

2023-05-16

JUC的多线程辅助类非常多,这里我们介绍三个:

  1. CountDownLatch(倒计数器)

  2. CyclicBarrier(循环栅栏)

  3. Semaphore(信号量)

1. CountDownLatch

CountDownLatch是一个非常实用的多线程控制工具类,应用非常广泛。

例如:在手机上安装一个应用程序,假如需要5个子进程检查服务授权,那么主进程会维护一个计数器,初始计数就是5。用户每同意一个授权该计数器减1,当计数减为0时,主进程才启动,否则就只有阻塞等待了。

CountDownLatch中count down是倒数的意思,latch则是门闩的含义。整体含义可以理解为倒数的门栓,似乎有一点“三二一,芝麻开门”的感觉。CountDownLatch的作用也是如此。

常用的就下面几个方法:

new CountDownLatch(int count)  //实例化一个倒计数器,count指定初始计数
countDown()  // 每调用一次,计数减一
await()  //等待,当计数减到0时,阻塞线程(可以是一个,也可以是多个)并行执行

案例:6个同学陆续离开教室后值班同学才可以关门。  

public class CountDownLatchDemo {

    /**
     * main方法也是一个进程,在这里是主进程,即上锁的同学
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {

        // 初始化计数器,初始计数为6
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                try {
                    // 每个同学墨迹几秒钟
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + " 同学出门了");
                    // 调用countDown()计算减1
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }

        // 调用计算器的await方法,等待6位同学都出来
        countDownLatch.await();

        System.out.println("值班同学锁门了");
    }
}

2. CyclicBarrier

从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。该命令只在每个屏障点运行一次。若在所有参与线程之前更新共享状态,此屏障操作很有用。

常用方法:

  1. CyclicBarrier(int parties, Runnable barrierAction) 创建一个CyclicBarrier实例,parties指定参与相互等待的线程数,barrierAction一个可选的Runnable命令,该命令只在每个屏障点运行一次,可以在执行后续业务之前共享状态。该操作由最后一个进入屏障点的线程执行。

  2. CyclicBarrier(int parties) 创建一个CyclicBarrier实例,parties指定参与相互等待的线程数。

  3. await() 该方法被调用时表示当前线程已经到达屏障点,当前线程阻塞进入休眠状态,直到所有线程都到达屏障点,当前线程才会被唤醒。

案例:组队打boss过关卡游戏。

注意:所有的"过关了"都是由最后到达await方法的线程执行打印的。

public class CyclicBarrierDemo {

    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {

            System.out.println(Thread.currentThread().getName() + " 过关了");
        });

        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + " 开始第一关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(4));
                    System.out.println(Thread.currentThread().getName() + " 开始打boss");
                    cyclicBarrier.await();

                    System.out.println(Thread.currentThread().getName() + " 开始第二关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(4));
                    System.out.println(Thread.currentThread().getName() + " 开始打boss");
                    cyclicBarrier.await();

                    System.out.println(Thread.currentThread().getName() + " 开始第三关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(4));
                    System.out.println(Thread.currentThread().getName() + " 开始打boss");
                    cyclicBarrier.await();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

3. Semaphore

Semaphore翻译成字面意思为 信号量,Semaphore可以控制同时访问的线程个数。非常适合需求量大,而资源又很紧张的情况。比如给定一个资源数目有限的资源池,假设资源数目为N,每一个线程均可获取一个资源,但是当资源分配完毕时,后来线程需要阻塞等待,直到前面已持有资源的线程释放资源之后才能继续。

常用方法:

public Semaphore(int permits) // 构造方法,permits指资源数目(信号量)
public void acquire() throws InterruptedException // 占用资源,当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时。
public void release() // (释放)实际上会将信号量的值加1,然后唤醒等待的线程。

信号量主要用于两个目的:

  1. 多个共享资源的互斥使用。

  2. 用于并发线程数的控制。保护一个关键部分不要一次输入超过N个线程。

案例:6辆车抢占3个车位

public class SemaphoreDemo {

    public static void main(String[] args) {
        // 初始化信号量,3个车位
        Semaphore semaphore = new Semaphore(3);

        // 6个线程,模拟6辆车
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                try {
                    // 抢占一个停车位
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 抢到了一个停车位!!");
                    // 停一会儿车
                    TimeUnit.SECONDS.sleep(new Random().nextInt(10));
                    System.out.println(Thread.currentThread().getName() + " 离开停车位!!");
                    // 开走,释放一个停车位
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

05_JUC强大的辅助类 的相关文章

随机推荐

  • android遇到的问题的总结----Activity和fragment之间相互跳转

    一 activity与activity之间跳转 xff1a span class token comment 第一个参数是上下文 span span class token comment 第二个参数是将要跳转的activity span
  • maven项目创建MyBatis教程

    先创建一个新的maven项目 然后把配置文件放pom xml中在刷新导入 span class token operator lt span dependencies span class token operator gt span sp
  • Vue3中axios的使用与封装

    文章目录 一 安装axios二 配置与封装三 引入与使用 一 安装axios span class token function npm span i axios s 二 配置与封装 src aixos request js http js
  • MySQL常见七种通用的Join查询练习题

    准备数据库表 t dept 和 t emp CREATE TABLE 96 t dept 96 96 id 96 int NOT NULL AUTO INCREMENT 96 deptName 96 varchar 30 DEFAULT N
  • MySQL索引分类

    主键索引 xff1a 设定为主键后数据库会自动建立索引 xff0c innodb为聚簇索引 单值索引 xff1a 即一个索引只包含单个列 xff0c 一个表可以有多个单列索引 唯一索引 xff1a 索引列的值必须唯一 xff0c 但允许有空
  • Docker 部署 MySQL 一主多从

    主从复制的原理 xff1a 1 主库 xff1a 创建一个有权访问binlog日志的从库账号 xff0c 配置需要主从复制的库 有写操作时 xff0c 可以将写操作或者写操作之后的数据记录到日志文件中 binlog 通过一个线程通知需要同步
  • Java笔记(8)——重载(Overload)与重写(Override)的区别

    1 重写 xff08 Override xff09 重写是子类对允许访问的父类的方法进行重新编写的过程 xff0c 方法名 返回值和参数列表不能变 xff0c 方法中的内容可以变化 特点就是 xff1a 子类可以根据自己的需要对父类的方法进
  • ShardingSphere介绍

    官网 xff1a https shardingsphere apache org index zh html 文档 xff1a https shardingsphere apache org document 5 1 1 cn overvi
  • ShardingSphere-JDBC读写分离

    基于之前搭建的mysql主从读写分离使用ShardingSphere JDBC实现读写分离 参考文章 xff1a Docker 部署 MySQL 一主多从 书启秋枫的博客 CSDN博客 CREATE DATABASE mydb2 USE m
  • ShardingSphere-JDBC垂直分片

    什么是数据分片 xff1f 简单来说 xff0c 就是指通过某种特定的条件 xff0c 将我们存放在同一个数据库中的数据分散存放到多个数据库 xff08 主机 xff09 上面 xff0c 以达到分散单台设备负载的效果 数据的切分 xff0
  • ShardingSphere-JDBC水平分片

    项目中可以使用ShardingSphere JDBC将数据存到不同库的表中 一 准备服务器 服务器规划 xff1a 使用docker方式创建如下容器 主服务器 xff1a 容器名server order0 xff0c 端口3310从服务器
  • ShardingSphere-JDBC绑定表

    一 什么是绑定表 指分片规则一致的一组分片表 使用绑定表进行多表关联查询时 xff0c 必须使用分片键进行关联 xff0c 否则会出现笛卡尔积关联或跨库关联 xff0c 从而影响查询效率 例如 xff1a t order 表和 t orde
  • ShardingSphere-JDBC广播表

    一 什么是广播表 指所有的分片数据源中都存在的表 xff0c 表结构及其数据在每个数据库中均完全一致 适用于数据量不大且需要与海量数据的表进行关联查询的场景 xff0c 例如 xff1a 字典表 广播具有以下特性 xff1a xff08 1
  • 01_JUC概述

    1 JUC是什么 xff1f 在 Java 5 0 提供了 java util concurrent 简称JUC 包 xff0c 在此包中增加了在并发编程中很常用的工具类 此包包括了几个小的 已标准化的可扩展框架 xff0c 并提供一些功能
  • 02_Lock锁

    首先看一下JUC的重磅武器 锁 xff08 Lock xff09 相比同步锁 xff0c JUC包中的Lock锁的功能更加强大 xff0c 它提供了各种各样的锁 xff08 公平锁 xff0c 非公平锁 xff0c 共享锁 xff0c 独占
  • 03_线程间通信

    面试题 xff1a 两个线程打印 两个线程 xff0c 一个线程打印1 52 xff0c 另一个打印字母A Z打印顺序为12A34B 5152Z xff0c 要求用线程间通信 public class Demo01 public stati
  • 04_并发容器类

    1 重现线程不安全 xff1a List 首先以List作为演示对象 xff0c 创建多个线程对List接口的常用实现类ArrayList进行add操作 public class NotSafeDemo public static void
  • Java笔记(10)——异常处理

    1 Java异常 Java运行时发生异常可以分为两类 xff1a Error xff1a JVM系统内部错误 资源耗尽等问题产生的异常 Exception xff1a 编程错误或偶然的外在因素导致的 2 常见的异常 2 1 RuntimeE
  • mariadb 数据库连接使用

    今天测试了使用mariadb的使用 xff0c 我使用的springboot 43 mariadb 来操作数据库 xff0c 和以前的代码基本一样 xff0c 就数据变成了mariadb xff0c 驱动还是使用mysql的 pom 文件如
  • 05_JUC强大的辅助类

    JUC的多线程辅助类非常多 xff0c 这里我们介绍三个 xff1a CountDownLatch xff08 倒计数器 xff09 CyclicBarrier xff08 循环栅栏 xff09 Semaphore xff08 信号量 xf