【JUC基础】08. 三大工具类

news2024/11/29 2:32:25

1、前言

JUC包中包含了三个非常实用的工具类:CountDownLatch(倒计数器),CyclicBarrier(循环栅栏),Semaphore(信号量)。

2、倒计数器:CountDownLatch

2.1、什么是CountDownLatch

英文中Count Down意为倒计数,Latch意为门闩,所以简单称之为倒计数器。门闩的含义就是把门锁起来,不让里面的线程跑出来。因此这个工具通常用来控制线程等待。它可以让某一个线程等待直到倒计时结束,在开始执行。

来看API文档:

相应API:

2.2、使用

如何使用,JDK API文档给出来了示例用法:CountDownLatch (Java Platform SE 8 )

  • 示例用法:

这是一组类,其中一组工作线程使用两个倒计时锁存器:

  • 第一个是启动信号,防止任何工作人员进入,直到驾驶员准备好继续前进;
  • 第二个是完成信号,允许司机等到所有的工作人员完成。
class Driver { 
    // ... 
    void main() throws InterruptedException { 
        CountDownLatch startSignal = new CountDownLatch(1); 
        CountDownLatch doneSignal = new CountDownLatch(N); 
        for (int i = 0; i < N; ++i) // create and start threads 
            new Thread(new Worker(startSignal, doneSignal)).start(); 
        doSomethingElse(); // don't let run yet startSignal.countDown(); // let all threads proceed doSomethingElse(); 
        doneSignal.await(); // wait for all to finish 
     } 
} 

class Worker implements Runnable { 
    private final CountDownLatch startSignal; 
    private final CountDownLatch doneSignal; 
    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { 
        this.startSignal = startSignal; 
        this.doneSignal = doneSignal; 
    } 
    
    public void run() { 
        try { 
            startSignal.await(); 
            doWork(); 
            doneSignal.countDown(); 
        } catch (InterruptedException ex) {
                    
        } 
        // return; 
    } 
    void doWork() { ... } 
} 

内存一致性效果:直到计数调用之前达到零,在一个线程操作countDown() happen-before以下由相应的成功返回行动await()在另一个线程。

示例代码:

场景:某一个程序测试期间发现10个bug,需要将10个bug全部修复完毕,才能进行上线。

package juc.util;

import cn.hutool.core.thread.ThreadUtil;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

/**
 * @author Shamee loop
 * @date 2023/5/16
 */
public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = ThreadUtil.newFixedExecutor(10, "countdownlatch-pool-", true);
        
        // 生成一个CountDownLatch实例,计数数量10。
        // 这里表示需要10个线程完成任务后,等待在CountDownLatch上的线程才能继续执行。
        CountDownLatch end = new CountDownLatch(10);

        for (int i = 1; i <= 10; i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    // 这里模拟bug修复时长1s
                    ThreadUtil.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + "第[" + finalI + "]个bug修复完成");
                } finally {
                    // 计数器减1
                    end.countDown();
                }
            });
        }
        // 等待所有任务全部完成,主线程才能继续执行
        end.await();
        System.out.println("bug全部修复完成,项目上线");
        // 关闭线程池
        executorService.shutdown();
    }
}

运行结果:

3、循环栅栏:CyclicBarrier

3.1、什么是CyclicBarrier

CyclicBarrier是另外一种多线程并发控制工具。和CountDownLatch类似,他也可以实现线程间的计数等待,但他的功能比CountDownLatch更强大且复杂。

Cyclic意为循环,Barrier意为障碍或栅栏。所以简单称之为循环栅栏。既然名为栅栏,顾名思义就是用来阻止线程继续执行,要求线程在栅栏外等待。既然是循环栅栏,也就是该计数器可以循环使用。如我们将计数器设置为10,那么凑齐一批10个线程后,计数器就会归零,接着凑齐下一批。

来看官方API文档:

相应API:

3.2、使用

CyclicBarrier (Java Platform SE 8 )

  • 示例用法:

以下是在并行分解设计中使用障碍的示例:

public class Solver {
    final int N;
    final float[][] data;
    final CyclicBarrier barrier;

    class Worker implements Runnable {
        int myRow;
        Worker(int row) {
            myRow = row; 
        }
        public void run() { 
            while (!done()) { 
                processRow(myRow); 
                try { 
                    barrier.await(); 
                } catch (InterruptedException ex) { 
                    return; 
                } catch (BrokenBarrierException ex) { 
                    return; 
                } 
            } 
        } 
    } 
    
    public Solver(float[][] matrix) { 
        data = matrix; 
        N = matrix.length; 
        Runnable barrierAction = new Runnable() { 
            public void run() { 
                mergeRows(...); 
            }
        }; 
        barrier = new CyclicBarrier(N, barrierAction); 
        List<Thread> threads = new ArrayList<Thread>(N); 
        for (int i = 0; i < N; i++) { 
            Thread thread = new Thread(new Worker(i)); 
            threads.add(thread); 
            thread.start(); 
        } // wait until done 
        for (Thread thread : threads) thread.join(); 
    } 
} 

这里,每个工作线程处理矩阵的一行,然后等待屏障,直到所有行都被处理。

当处理所有行时,执行提供的Runnable屏障操作并合并行。 如果合并确定已经找到解决方案,那么done()将返回true ,并且每个工作人员将终止。

如果屏障操作不依赖于执行方暂停的各方,那么该方可以在释放任何线程时执行该操作。 为了方便这一点,每次调用await()返回该线程在屏障上的到达索引。 然后,您可以选择哪个线程应该执行屏障操作,例如:

 if (barrier.await() == 0) { // log the completion of this iteration } 

CyclicBarrier对失败的同步尝试使用all-or-none断裂模型:如果线程由于中断,故障或超时而过早离开障碍点,那么在该障碍点等待的所有其他线程也将通过BrokenBarrierException (或InterruptedException)异常离开如果他们也在同一时间被打断)。

内存一致性效果:线程中调用的行动之前, await() happen-before行动是屏障操作的一部分,进而发生,之前的动作之后,从相应的成功返回await()其他线程。

示例代码:

场景:某团购活动,每3人报名,则团购组团成功。

package juc.util;

import cn.hutool.core.thread.ThreadUtil;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;

/**
 * @author Shamee loop
 * @date 2023/5/16
 */
public class CyclicBarrierTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = ThreadUtil.newFixedExecutor(3, "CyclicBarrier-Pool-", true);
        
        // 等待3人报名成功,打印组团成功
        CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("每3个人报名,则组团成功"));

        // 模拟10个人报名
        for (int i = 1; i <= 10; i++) {
            int finalI = i;
            executorService.submit(() -> {
                // 这里模拟每个人报名时长1s
                ThreadUtil.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "第[" + finalI + "]个报名成功");
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        // 关闭线程池
        executorService.shutdown();
    }
}

执行结果:

从执行结果来看,确实满足我们的预期。但是我们发现第10个人报名的时候永远凑不齐3人组团,所以主线程会一直等待下去。当然await()的时候可以给予在屏障点的等待超时时间,如果超过时间还没等待到,那么就超时退出,避免程序卡死。

注:CyclicBarrier对失败的同步尝试使用all-or-none断裂模型:如果线程由于中断,故障或超时而过早离开障碍点,那么在该障碍点等待的所有其他线程也将通过BrokenBarrierException (或InterruptedException)异常离开如果他们也在同一时间被打断)。

4、信号量:Semaphore

4.1、什么是Semaphore

Semaphore意为信号量。为多线程写作提供了更为强大的控制方法,可以说是对锁的扩展。无论对Synchronized或ReentrantLock,一次都只允许一个线程访问一个资源,而Semaphore可以指定多个线程同时访问某一个资源。

官方API文档说明:

相关API:

4.2、使用

Semaphore (Java Platform SE 8 )

  • 信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源。

例如,这是一个使用信号量来控制对一个项目池的访问的类:

public class Pool {
    private static final int MAX_AVAILABLE = 100;
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    public void putItem(Object x) {
        if (markAsUnused(x))
            available.release();
    }

    //     Not a particularly efficient data structure; just for demo
//    protected Object[] items = ... whatever kinds of items being managed 
    protected boolean[] used = new boolean[MAX_AVAILABLE];

    protected synchronized Object getNextAvailableItem() {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null; // not reached 
    }
    protected synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < MAX_AVAILABLE; ++i) {
            if (item == items[i]) {
                if (used[i]) 
                    used[i] = false;
                    return true;
                 else 
                    return false;
                
                return false;
            }
        }
    }
}

在获得项目之前,每个线程必须从信号量获取许可证,以确保某个项目可用。 当线程完成该项目后,它将返回到池中,并将许可证返回到信号量,允许另一个线程获取该项目。 请注意,当调用acquire()时,不会保持同步锁定,因为这将阻止某个项目返回到池中。 信号量封装了限制对池的访问所需的同步,与保持池本身一致性所需的任何同步分开。

关于信号量的场景,很多时候适用于单机限流中 ----即限制同时访问某资源的并发数。基本思路:让1个线程以固定的速度生产,而让多个线程消费,这样消费者线程就能以低于某个上限的速度消费资源,不会导致系统超负荷。

简单的场景如红绿灯,每次绿灯亮起只能通行3辆车,而此时5辆车正在排队。

示例代码:

package juc.util;

import cn.hutool.core.thread.ThreadUtil;

import java.util.concurrent.Semaphore;

/**
 * @author Shamee loop
 * @date 2023/5/17
 */
public class SemaphoreTest {
    public static void main(String[] args) {

        // 每次绿灯通行5辆车,即线程数量
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    // 得到绿灯通行凭证
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "======> 通行");
                    ThreadUtil.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + "=======!结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放凭证
                    semaphore.release();
                }
            }, "第" + i + "辆车").start();
        }
    }
}

执行结果:

可以看到每次至多只有3辆车可以通行。达到了类似限流的目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/550521.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Vue前后端分离机票预定/订购系统设计与实现(视频讲解)

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

章节2 Matplotlib 绘图基础

目录 课时 2 Matplotlib简介及绘制简单线型图 课时 3 图例和标题 课时 4 自定义图形样式 课时 4 绘制条形图 课时 2 Matplotlib简介及绘制简单线型图 线的画法 plt.plot&#xff0c;同时提供x轴坐标和y轴坐标 课时 3 图例和标题 x 轴数据默认即可&#xff0c;如下所示 x轴代…

SimpleDateFormat非线程安全问题

文章目录 1. SimpleDateFormat介绍2. 测试SimpleDateFormat的非线程安全性3. 解决方案一4. 解决方案二 1. SimpleDateFormat介绍 SimpleDateFormat是Java中的一个类&#xff0c;用于将日期对象格式化为特定的字符串表示形式&#xff0c;或者将特定格式的字符串解析为日期对象。…

netstat 连接通信的信息和状态、以及ss

netstat 常用参数 t 只显示tcpu只显示udpnnum 数字形式显示地址和端口号l listen 显示监听端口 pprogram 显示进程aall 所有连接和监听r显示路由表 netstat -lnp 显示服务监听端口tcpudpsocket &#xff0c;socket 文件也用来同一台服务器的进程之间通信的…

Spring中的MergedBeanDefinitionPostProcessor有什么作用 ?

Spring中的MergedBeanDefinitionPostProcessor有什么作用 ? 引言调用时机加载bean定义的几种方式postProcessMergedBeanDefinition接口作用小结 引言 MergedBeanDefinitionPostProcessor这个Bean后置处理器大家可能关注的比较少,其本身也只提供了一个bean生命周期回调接口: …

iptable 防火墙一

目录 iptables概述netfilter/iptables 关系四表五链四表&#xff1a;五链&#xff1a; 规则链之间的匹配顺序主机型防火墙&#xff1a;规则链内的匹配顺序&#xff1a; iptables 安装iptables防火墙的配置方法&#xff1a;iptables 命令行配置方法&#xff1a;常用的控制类型&a…

一文读懂大语言模型

以ChatGPT为代表的大语言模型被很多人认为是新一轮科技革命的起点&#xff0c;本文旨在通过概念性介绍&#xff0c;让普通人能够尽可能理解人工智能以及大语言模型的基本概念&#xff0c;从而了解这些技术能做以及不能做什么。原文: A Very Gentle Introduction to Large Langu…

v4l2数据结构分析

v4l2数据结构分析 文章目录 v4l2数据结构分析Video4Linux2设备v4l2_device媒体设备media_deviceVideo4Linux2子设备v4l2_subdevVideo4Linux2子设备的操作集v4l2_subdev_opsVideo4Linux2子设备的内部操作集v4l2_subdev_internal_opsVideo4Linux2控制处理器v4l2_ctrl_handlerVide…

微信自动聊天机器狗,配置chatGPT,比Siri还智能!

大家好&#xff0c;我是TheWeiJun&#xff1b;最近看见微信里各个群聊都在聊chatGPT&#xff0c;甚至有的大佬们都把chatGPT接入了微信群聊&#xff0c;于是就有粉丝来找小编&#xff0c;希望能出一期chatGPT的文章&#xff1b;故今天这篇文章我将手把手教大家如何实现并自定义…

学习《信息系统项目管理师教程》第4版应关注的PMBOK的巨大变化

学习《信息系统项目管理师教程》第4版应关注的PMBOK的巨大变化 《信息系统项目管理师教程》的第4版比起第3版来有不少变化。但是&#xff0c;这种变化完全没有体现出PMBOK第7版带来的巨大变化。 因为&#xff0c;在从《信息系统项目管理师教程》第3版出版的2017年到现在&…

uvc驱动中的v4l2

uvc驱动中的v4l2 文章目录 uvc驱动中的v4l2v4l2_device_registervideo_register_devicev4l2_ioctlsvideo_usercopy v4l2_device_register /driver/media/v4l2-core/v4l2-device.c uvc_probe->v4l2_device_register v4l2_device_register 只是用于初始化一些东西&#xff0c…

【数项级数】无穷个数相加一定是个数吗?

数项级数 引入思考问题转化 定义总结重要的例子练习题 引入 思考 数项级数&#xff0c;其实就是要解决无穷个数相加的问题。 而对于无穷求和的问题&#xff0c;思考&#xff1a;无穷个数相加一定是个数吗&#xff1f; 下面&#xff0c;我们来举几个例子&#xff1a; 1 2 2 …

创世纪:比特币诞生记

比特币的诞生 1. 创始区块2. 第一个举手的人3. 比特币的疯狂 1. 创始区块 2008年10月31日纽约时间下午2点10分&#xff0c;自称中本聪的人向一个邮件列表&#xff0c;包括密码学专家和爱好者几百个成员&#xff0c;发送了一封电子邮件。“我一直在研究一个新的电子现金系统&am…

springboot旅游资源管理系统门票酒店预订系统_b0a6b

Spring Boot 是 Spring 家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程。也可以说 Spring Boot 能简化我们之前采用SSM&#xff08;Spring MVC Spring MyBatis &#xff09;框架进行开发的过程。config&#xff1a;主要用来存储配置文件&#…

chatgpt赋能Python-pythoncontinue怎么用

Python continue语句&#xff1a;提高代码效率的绝佳工具 什么是Python continue语句&#xff1f; Python的continue语句可以使循环跳过当前的迭代。这意味着如果在循环内部存在满足某特定条件的语句&#xff0c;那么我们就可以使用continue语句跳过当前循环。Python中的cont…

【Nodejs】使用Nodejs搭建HTTP服务,并实现公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 转载自内网穿透工具的文章&#xff1a;使用Nodejs搭建HTTP服务&#xff0c;并实现公网远程访问「内网穿透」 前言 Node.js…

Mybatis Plus实现乐观锁

文章目录 1 概念2 实现思路3 实现步骤步骤1:数据库表添加列步骤2:在模型类中添加对应的属性步骤3:添加乐观锁的拦截器步骤4:执行更新操作 1 概念 在讲解乐观锁之前&#xff0c;我们还是先来分析下问题: 业务并发现象带来的问题 : 秒杀 假如有100个商品或者票在出售&#xff…

【数据分享】我国各县1992—2019年社会经济指标(7个指标\无需转发)

社会经济指标常用于各项研究中&#xff0c;之前基于《中国城市统计年鉴》我们整理了1999-2020年地级市的地区生产总值及一二三产构成数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01; 我们发现在学者Chen Yahan在Figshare 数据库中提供了1992—2019年以县为…

动态规划-状态压缩DP

[SCOI2005] 互不侵犯 题目描述 https://www.luogu.com.cn/problem/P1896 在NN的棋盘里面放K个国王&#xff0c;使他们互不攻击&#xff0c;共有多少种摆放方案。国王能攻击到它上下左右&#xff0c;以及左上左下右上右下八个方向上附近的各一个格子&#xff0c;共8个格子。 …

ADS-B接收机Radarcape

1.设备简介 Radarcape是一款便携、高性能、功能强大的ADS-B地面接收机。Radarcape的设备清单包含&#xff1a;ADS-B接收机主机&#xff0c;专业级ADS-B天线&#xff0c;GPS天线&#xff0c;电源线&#xff0c;网线。 2. 功能特点 Radarcape可以通过网口输出飞机的原始数据D…