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

目录

  • 一、简介
  • 二、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(信号量,限制并发数量)

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ADF4351】使用FPGA进行SPI寄存器配置、使用FPGA计算各个频率的频点,ADF4351配置程序

简介 特性 输出频率范围&#xff1a;35 MHz至4,400 MHz 小数N分频频率合成器和整数N分频频率合成器 具有低相位噪声的VCO 可编程的1/2/4/8/16/32/64分频输出 典型抖动&#xff1a;0.3 ps rms EVM(典型值&#xff0c;2.1 GHz)&#xff1a; 0.4% 电源&#xff1a;3.0 V至3.6 V …

Acwing.2060 奶牛选美(DFS)

题目 听说最近两斑点的奶牛最受欢迎&#xff0c;约翰立即购进了一批两斑点牛。 不幸的是&#xff0c;时尚潮流往往变化很快&#xff0c;当前最受欢迎的牛变成了一斑点牛。 约翰希望通过给每头奶牛涂色&#xff0c;使得它们身上的两个斑点能够合为一个斑点&#xff0c;让它们…

构建卓越数据应用体系,释放企业数据资产的最大价值

随着数字化浪潮的汹涌而至&#xff0c;数据已经成为驱动社会发展的重要资源。在这个信息爆炸的时代&#xff0c;如何有效地收集、管理、分析和应用数据&#xff0c;成为摆在我们面前的一大挑战。数据应用体系的建设&#xff0c;不仅关乎企业竞争力的提升&#xff0c;更是推动整…

前端模块化开发

模块化发展历程 一个模块单独抽离成一个文件&#xff0c;&#xff08;缺点&#xff1a; 命名冲突&#xff0c;全靠约定&#xff09;命名空间的方式&#xff0c;导出一个对象&#xff08;确定&#xff1a;命名冲突还是存在&#xff0c;可在外部修改&#xff0c;没解决依赖关系的…

fastadmin实验教学管理最近新增功能的技术盘点

在与用户交流中&#xff0c;发现了有些功能不够便捷&#xff0c;特抽出时间优化了一下 一键锁定 优化背景&#xff1a;先通过实验日期或实验名称先搜索&#xff0c;然后选中对应的复选框&#xff0c;再点击“锁定”&#xff0c;这样容易漏选或错选 1.工具栏新增自定义按钮“一…

目标检测——PP-YOLOv2算法解读

PP-YOLO系列&#xff0c;均是基于百度自研PaddlePaddle深度学习框架发布的算法&#xff0c;2020年基于YOLOv3改进发布PP-YOLO&#xff0c;2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet&#xff0c;2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列&#xff0c;所以放一起解…

面向未来的前沿人工智能监管

策制定者应该为未来十年人工智能系统更加强大的世界做好准备。这些发展可能会在人工智能科学没有根本性突破的情况下发生&#xff0c;只需扩展当今的技术以在更多数据和计算上训练更大的模型即可。 用于训练前沿人工智能模型的计算量在未来十年可能会显着增加。到 2020 年代末…

Linux初识环境变量

&#x1f30e;环境变量【上】 文章目录&#xff1a; 环境变量 什么是环境变量 关于命令行参数 环境变量       简单了解       为什么需要环境变量       系统中其他环境变量 总结 前言&#xff1a; 环境变量是一种非常重要的概念&#xff0c;它们对于系统的…

springboot酒店管理系统 论文【源码】

springboot酒店管理系统开发说明 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1…

路由器级联

目录 一、实现功能二、实现步骤2.1 接线步骤 三、效果3.1 常规连接3.2 路由器级联 一、实现功能 主路由器&#xff1a;可有WiFi功能&#xff0c;LAN口下接各设备&#xff0c;并接一个辅路由器辅路由器&#xff1a;开启WiFi功能&#xff0c;有线或无线下接各设备功能&#xff1…

长安链正式发布三周年,技术更迭支撑产业变革

导语&#xff1a; 2024年1月27日长安链正式发布三周年&#xff0c;开源社区借开年之际与大家一同回顾长安链三年来的技术发展历程&#xff0c;每一个里程碑的建设都得益于与长安链同行的合作伙伴与开发者&#xff0c;希望在2024年可以共同携手继往开来&#xff0c;为数字经济发…

深入浅出前端本地储存(1)

引言 2021 年&#xff0c;如果你的前端应用&#xff0c;需要在浏览器上保存数据&#xff0c;有三个主流方案&#xff1a; CookieWeb Storage (LocalStorage)IndexedDB 这些方案就是如今应用最广、浏览器兼容性最高的三种前端储存方案 今天这篇文章就聊一聊这三种方案的历史…

安装vcenter管理esxi

安装vcenter管理esxi虚拟化操作系统 文章目录 安装vcenter管理esxi虚拟化操作系统1.安装vcenter2.vcenter的应用 1.安装vcenter esxi虚拟机具体安装步骤请参考上一篇文章&#xff0c;vcenter软件包需自己到网上下 2.vcenter的应用

蚓链帮助企业对资源进行数字化整合,加速变现实现利他多赢!

​蚓链作为一种数字化资源整合的工具或平台&#xff0c;可以帮助企业实现数字化资源整合。在当前的数字化时代&#xff0c;各种信息和资源呈现出乘方式的增长。企业要想在竞争中脱颖而出&#xff0c;就需要对这些资源进行有效的整合和利用。蚓链通过提供一套完善的数字化解决方…

Flutter Plugin中依赖aar本地包

一、首先在项目的根目录的build.gradle中&#xff0c;添加如下代码 allprojects {repositories {//...flatDir {//pay_2c2p就是你的flutter plugin插件名称dirs project(:pay_2c2p).file(libs)}} }二、然后到Plugin的android目录中 &#xff0c;在src目录的同级创建libs目录将…

Java安全基础 必备概念理解

Java安全基础 关键概念汇总 文章目录 Java安全基础 关键概念汇总前置知识1.构造器this以及包的使用2.继承3.重写/ 重载 / super4.多态5.区分和equals方法6.toString的使用7.Object的概念8.static,final,代码块static代码块final 9.动态代理10.类的动态加载1)类加载器含义&#…

LeetCode 热题 100 | 回溯(三)

目录 1 131. 分割回文串 2 51. N 皇后 菜鸟做题&#xff0c;语言是 C&#xff0c;感冒好了 ver. 1 131. 分割回文串 题眼&#xff1a;给你一个字符串 s&#xff0c;请你将 s 分割 成一些子串。 根据题眼可知&#xff0c;我们需要做的是将字符串 s 连续分割 为几段&#…

医保智慧购药:探索医保买药小程序技术开发与应用

如今&#xff0c;医保智慧购药成为了一种趋势&#xff0c;尤其是医保买药小程序的技术开发和应用&#xff0c;为患者提供了更加便捷、高效的医药购买体验。 医保买药小程序是一种基于手机移动终端的应用程序&#xff0c;它通过智能化的算法和医保系统的对接&#xff0c;为患者…

gPTP简介

1、gPTP&#xff08;generalized precision time protocol&#xff09;广义时钟同步协议 gPTP&#xff08;generalized precision time protocol&#xff09;广义时钟同步协议&#xff0c;即IEEE 802.1AS协议。它是IEEE 1588协议的延伸&#xff0c;可以为TSN提供全局精准…

Legacy|电脑Windows系统如何迁移到新安装的硬盘?系统迁移详细教程!

前言 前面讲了很多很多关于安装系统、重装系统的教程。但唯独没有讲到电脑换了新的硬盘之后&#xff0c;怎么把旧系统迁移到新的硬盘上。 今天小白就来跟各位小伙伴详细唠唠&#xff1a; 开始之前需要把系统迁移的条件准备好&#xff0c;意思就是在WinPE系统下&#xff0c;可…