并发编程Semaphore(信号量)浅析

news2024/11/15 21:49:25

目录

  • 一、简介
  • 二、API
  • 三、使用
    • 3.1 demo1
    • 3.1 demo2
  • 四、适用场景


一、简介

Semaphore(信号量)是 Java 中用于控制同时访问特定资源的线程数量的工具类。Semaphore 维护了一组许可证,线程在访问资源之前必须先获取许可证,访问完毕后再释放许可证,从而限制同时访问资源的线程数量。

Semaphore 主要包括两个核心方法:

acquire(): 当一个线程希望访问资源时,调用 acquire() 方法来获取一个许可证。如果当前没有可用的许可证,线程将被阻塞,直到有可用的许可证为止。
release(): 当一个线程访问资源完毕后,调用 release() 方法来释放一个许可证,使其他等待许可证的线程可以继续执行。

除了上述方法外,Semaphore 还提供了一些其他方法来获取当前可用的许可证数量、设置初始许可证数量等。


二、API

  • 非公平
    public Semaphore(int permits);//permits就是允许同时运行的线程数目
  • 公平
    public Semaphore(int permits,boolean fair);//permits就是允许同时运行的线程数目,fair=true代表公平
  • 创建一个信号量
    Semaphore semaphore = new Semaphore(int permits);
  • 从信号量中获取一个许可
    semaphore.acquire();
  • 释放一个许可(在释放许可之前,必须先获获得许可。)
    semaphore.release();
  • 尝试获取一个许可,若获取成功返回true,若获取失败返回false
    semaphore.tryAcquire();
  • // 创建具有给定的许可数和非公平的公平设置的 Semaphore。
    Semaphore(int permits)
  • // 创建具有给定的许可数和给定的公平设置的 Semaphore。
    Semaphore(int permits, boolean fair)
  • // 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
    void acquire()
  • // 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。
    void acquire(int permits)
  • // 从此信号量中获取许可,在有可用的许可前将其阻塞。
    void acquireUninterruptibly()
  • // 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
    void acquireUninterruptibly(int permits)
  • // 返回此信号量中当前可用的许可数。
    int availablePermits()
  • // 获取并返回立即可用的所有许可。
    int drainPermits()
  • // 返回一个 collection,包含可能等待获取的线程。
    protected Collection< Thread> getQueuedThreads()
  • // 返回正在等待获取的线程的估计数目。
    int getQueueLength()
  • // 查询是否有线程正在等待获取。
    boolean hasQueuedThreads()
  • // 如果此信号量的公平设置为 true,则返回 true。
    boolean isFair()
  • // 根据指定的缩减量减小可用许可的数目。
    protected void reducePermits(int reduction)
  • // 释放一个许可,将其返回给信号量。
    void release()
  • // 释放给定数目的许可,将其返回到信号量。
    void release(int permits)
  • // 返回标识此信号量的字符串,以及信号量的状态。
    String toString()
  • // 仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
    boolean tryAcquire()
  • // 仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
    boolean tryAcquire(int permits)
  • // 如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
    boolean tryAcquire(int permits, long timeout, TimeUnit unit)
  • // 如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。
    boolean tryAcquire(long timeout, TimeUnit unit)

三、使用

3.1 demo1

简单的示例代码,演示了如何使用 Semaphore:

public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // 初始化一个许可证数量为2的 Semaphore

        // 创建多个线程尝试获取许可证
        for (int i = 1; i <= 5; i++) {
            final int threadId = i;
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println("Thread " + threadId + " acquired the permit.");
                    Thread.sleep(2000); // 模拟线程在访问资源
                    semaphore.release();
                    System.out.println("Thread " + threadId + " released the permit.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

输出:呃,只看到了获取和释放信号量,好像并不能看出同时运行的线程数。
在这里插入图片描述

3.1 demo2

假设有30个人在超市支付结算,只有3个结算窗口,代码实现逻辑如下

    public static void test3() {
        // 排队总人数(请求总数)
        int clientTotal = 30;
        // 可同时结算商品的窗口数量(同时并发执行的线程数)
        int threadTotal = 3;

        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            final int count = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire(1);
                    payment(count);
                    semaphore.release(1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
      	    executorService.shutdown();
    }

    private static void payment(int i) throws InterruptedException {
        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss z");
        Date date = new Date(System.currentTimeMillis());
        System.out.println(Thread.currentThread().getName() + " 支付结算中" + formatter.format(date));
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

输出:明显看到同一时间三个线程在运行,并且间隔两秒释放信号量。
在这里插入图片描述

四、适用场景

Semaphore 可以用于多种场景,例如:

连接池管理: 在数据库连接池、线程池等资源池中,可以使用 Semaphore 来限制同时获取资源的线程数量,避免资源被过度占用。
并发访问控制: 在多线程环境下,可以使用 Semaphore 控制同时访问共享资源的线程数量,确保线程安全性。
流量控制: 在网络编程中,可以使用 Semaphore 来控制并发访问量,限制系统的并发连接数,防止系统被过度请求压垮。
生产者-消费者模式: 在生产者-消费者模式中,可以使用 Semaphore 来控制生产者和消费者之间的同步,确保生产者和消费者之间的协调工作。
限流控制: 在微服务架构中,可以使用 Semaphore 控制服务之间的调用频率,避免某个服务被过度调用而导致系统崩溃。
任务调度控制: 在任务调度系统中,可以使用 Semaphore 控制同时执行的任务数量,避免系统资源被过度占用。
缓存控制: 在缓存系统中,可以使用 Semaphore 控制对缓存的并发访问,避免缓存击穿和缓存雪崩等问题。

Semaphore 可以用于任何需要控制并发访问数量的场景,帮助实现线程安全和资源管理。在实际开发中,使用 Semaphore 可以提高系统的稳定性和性能。

参考链接:
java锁之Semaphore(信号量,限制并发数量)

在这里插入图片描述

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

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

相关文章

前端 -- 基础 表单标签 -- 表单域

表单域 # 表单域是一个包含 表单元素 的区域 在 HTML 标签中&#xff0c; <form> 标签 用于定义表单域&#xff0c; 以实现用户信息的收集和传递 简单通俗讲&#xff0c; 就是 <form> 会把它范围内的表单元素信息提交给后台&#xff08;服务器) 对于上面讲…

1058:求一元二次方程

【题目描述】 利用公式 求一元二次方程axbxc0的根&#xff0c;其中a不等于0。结果要求精确到小数点后5位。 【输入】 输入一行&#xff0c;包含三个浮点数a,b,c&#xff08;它们之间以一个空格分开&#xff09;&#xff0c;分别表示方程axbxc0的系数。 【输出】 输出一行&…

蓝桥杯 2023 省B 接龙数列

思路分析&#xff1a; 创建一个大小为10的向量 hash&#xff0c;用于记录以每个数字结尾的字符串数量。输入字符串数量 n。循环读取每个字符串&#xff0c;并更新 hash 中以当前字符串结尾的字符串数量。同时更新最大字符串数量 count。输出不可达的字符串数量&#xff0c;即 …

掘根宝典之C++正向迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…

鸿蒙-自定义组件-语法

目录 语法组成 在学习自定义组件前&#xff0c;先看一下ArkTS的组成 装饰器 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、Component和State都是装饰器 Entry 表示该自定义组件为入口组件 Component 表示自定义组件 State 表示组…

Html+threejs数字孪生三维场景实现

程序示例精选 Htmlthreejs数字孪生三维场景实现 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Htmlthreejs数字孪生三维场景实现》编写代码&#xff0c;代码整洁&#xff0c;规则&#xf…

【机器学习】基于机器学习的分类算法对比实验

摘要 基于机器学习的分类算法对比实验 本论文旨在对常见的分类算法进行综合比较和评估&#xff0c;并探索它们在机器学习分类领域的应用。实验结果显示&#xff0c;随机森林模型在CIFAR-10数据集上的精确度为0.4654&#xff0c;CatBoost模型为0.4916&#xff0c;XGBoost模型为…

高端竞赛活动中的软硬件供应商要如何选择

知识竞赛活动属于“直播”类活动&#xff0c;一旦开始无法重来&#xff0c;所以软硬件稳定可靠至关重要&#xff0c;要历经多次活动的磨炼&#xff0c;性能稳定可靠&#xff0c;要有多重防灾难设计和备用方案。所以一定要选择历经磨炼的高端竞赛软件和执行团队。 可以从以下几个…

好书推荐 《ARM汇编与逆向工程 蓝狐卷 基础知识》

《ARM 汇编与逆向工程 蓝狐卷 基础知识》 与传统的 CISC&#xff08;Complex Instruction Set Computer&#xff0c;复杂指令集计算机&#xff09;架构相比&#xff0c;Arm 架构的指令集更加简洁明了&#xff0c;指令执行效率更高&#xff0c;能够在更低的功耗下完成同样的计…

【Ubuntu】FTP站点搭建

配置顺序 前提条件&#xff1a;确保软件仓库可以正常使用&#xff0c;确保已正常配置IP地址 1.安装FTP服务 2.编辑FTP配置文件 3.设置开机自启 4.创建用户 5.配置用户限制名单 6.重启服务 7.查看运行状态 8.测试在同一局域网下的Windows查看文件 1.安装FTP服务 sudo apt insta…

AWS监控,AWS 性能监控工具

监控云部署的性能是 IT 环境正常运行的内在条件。AWS 云是一个架构良好的框架&#xff0c;管理员可以使用专用的AWS 性能监控工具增强服务的功能。执行AWS监视是为了跟踪在AWS环境中积极运行的应用程序工作负载和资源。AWS监视器跟踪各种AWS云指标&#xff0c;以帮助提高在其上…

html--蝴蝶

<!DOCTYPE html> <html lang"en" > <head> <meta charset"UTF-8"> <title>蝴蝶飞舞</title> <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.cs…

使用Navicat远程连接Linux中的MySQL

一、登录MySQL数据库 mysql -uroot -pXjm123456 二、使用mysql数据库 use mysql&#xff1b; 三、查询user表中包含host的字段 select user,host from user;### 该字段中&#xff0c;localhost表示只允许本机访问&#xff0c;可以将‘localhost’改为‘%’&#xff0c;‘%’表…

目标检测——YOLOv4算法解读

论文&#xff1a;YOLOv4&#xff1a;Optimal Speed and Accuracy of Object Detection 作者&#xff1a;Alexey Bochkovskiy, Chien-Yao Wang, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/pdf/2004.10934.pdf 代码&#xff1a;https://github.com/AlexeyAB/darkne…

【洛谷 P9232】[蓝桥杯 2023 省 A] 更小的数 题解(字符串+区间DP)

[蓝桥杯 2023 省 A] 更小的数 题目描述 小蓝有一个长度均为 n n n 且仅由数字字符 0 ∼ 9 0 \sim 9 0∼9 组成的字符串&#xff0c;下标从 0 0 0 到 n − 1 n-1 n−1&#xff0c;你可以将其视作是一个具有 n n n 位的十进制数字 n u m num num&#xff0c;小蓝可以从 n…

数据结构奇妙旅程之红黑树

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

【Selenium(四)】

一、浏览器操作 1、设置浏览器缩放大小 driver.set_window_size(长,宽) 2、浏览器的前进后退 #前进 driver.forward()#后退 driver.back() 3、浏览器的刷新 driver.refresh() 二、webdriver常见方法

#linux(使用apt-get下载)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;设置下载源 &#xff08;2&#xff09;在终端切换到root&#xff0c;然后输入apt-get update更新下载源 &#xff08;3&#xff09;安装一…

MATLAB的使用(一)

一&#xff0c;MATLAB的编程特点 a,语法高度简化&#xff1b; b,脚本式解释型语言&#xff1b; c,针对矩阵的高性能运算&#xff1b; d,丰富的函数工具箱支持&#xff1b; e,通过matlab本体构建跨平台&#xff1b; 二&#xff0c;MATLAB的界面 工具栏:提供快捷操作编辑器…

【机器学习】无监督学习算法之:自编码器

自编码器 1、引言2、自编码器2.1 定义2.2 原理2.3 实现方式2.4 算法公式2.5 代码示例 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 今天可以讲一讲 自编码器嘛 小鱼&#xff1a;请说清楚&#xff0c;是什么编码器&#xff1f; 小屌丝&#xff1a;自编码器 小鱼&#…