Semaphore解决高并发场景下的有限资源的并发访问问题

news2025/5/21 5:45:41
在高并发编程的领域中,我们常常面临着对有限资源的激烈抢夺问题。而 Java 的 java.util.concurrent 包提供的 Semaphore ,为我们提供了精准控制对有限资源并发访问的强大能力。

一、Semaphore

Semaphore,直译为 “信号量”,在多线程编程中扮演着至关重要的角色。它允许多个线程按照设定的规则访问某些有限的资源。就像是进入一间只有特定数量座位的会议室,每个线程如同参会人员,想要进入会议室(访问资源),必须先获取相应的许可(信号量);而当线程使用完资源后,必须释放信号量,以便其他线程能够获取许可进入。

二、Semaphore 的主要方法解读

  1. Semaphore(int permits):这是 Semaphore 的构造方法,其中的 permits 参数明确表示允许同时访问资源的数量,也就是我们为资源设定的 “准入名额”。例如,在停车场场景中,permits 可以设定为停车场的车位数量。
  2. acquire():当线程调用此方法时,就如同参会人员向会议组织者申请进入会议室。如果此时有可用的许可证(即有空闲资源),则该线程可以获取许可,同时内部维护的计数器减 1,表示一个资源被占用;若当前没有可用许可证,线程会被无情地阻塞,只能耐心等待,直到有许可证被释放。
  3. release():线程调用此方法,意味着使用完资源后归还许可证。当调用 release() 时,内部计数器加 1,表示一个资源被释放。如果此时有其他线程正在苦苦等待许可证,那么其中一个等待线程将被幸运地唤醒,获得访问资源的机会。
  4. availablePermits():这个方法就像一个实时资源状态监视器,它会返回当前可用的许可证数量,让线程随时了解还有多少资源可供使用。
  5. tryAcquire():线程调用此方法尝试获取一个许可证。与 acquire() 不同的是,如果当前没有许可证可用,它不会傻傻地阻塞线程,而是直接返回 false,给线程提供了一种更灵活的资源获取策略。

三、Semaphore 的核心机制剖析

Semaphore 的核心功能在于通过维护一个计数器来巧妙地控制并发线程的数量。当线程调用 acquire() 时,计数器减 1,表明有一个资源被占用;而当线程调用 release() 时,计数器加 1,意味着一个资源被释放。一旦计数器的值变为 0,后续调用 acquire() 的线程就会被阻塞,只能等待,直到有其他线程释放资源,计数器的值增加,才有机会获取许可,继续执行。

四、停车场场景

为了更直观地理解 Semaphore 在实际场景中的应用,我们来看一个停车场停车的例子。假设停车场只有 2 个车位,车辆会停留一段时间后离开。如何保证同一时刻最多有2辆车停在停车位呢?

import java.util.Random;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    private static final int CARS = 6;
    // 车位个数,只有两个
    private static Semaphore semaphore = new Semaphore(2, true);

    private static void park() {
        for (int i = 1; i <= CARS; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    // 看看有没有空车位
                    if (semaphore.availablePermits() == 0) {
                        System.out.println("第" + finalI + "辆司机,还没有空停车位,继续排队");
                    }
                    // 尝试进入停车位
                    semaphore.acquire();
                    System.out.println("第" + finalI + "成功进入停车场");
                    Thread.sleep(new Random().nextInt(10000));
                    System.out.println("第" + finalI + "驶出停车场");
                    // 离开停车场
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }).start();
        }
    }

    public static void main(String[] args) {
        park();
    }
}

我们首先定义了 CARS 常量,表示有 6 辆车。同时创建了一个 Semaphore 对象 semaphore,并通过构造函数设定其初始许可数量为 2,且设置为公平模式(true),这意味着等待时间最长的线程将优先获得许可。

park() 方法中,我们启动了 6 个线程来模拟 6 辆车。每个线程在尝试获取许可证前,先通过 availablePermits() 方法查看是否有空余车位。如果没有,就打印提示信息表示继续排队。然后调用 acquire() 方法尝试获取许可进入停车场。

一旦成功进入,车辆会随机停留一段时间(通过 Thread.sleep 模拟),之后调用 release() 方法释放许可证,表示车辆驶出停车场。

通过这个例子,我们可以清晰地看到 Semaphore 如何有效地控制对有限资源(停车位)的并发访问,确保在任何时刻,停车场内的车辆数量都不会超过其容量。

在高并发编程中,Semaphore 是一个强大而实用的工具,能够帮助我们优雅地解决资源竞争问题。

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

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

相关文章

Vue3——Pinia

目录 什么是 Pinia&#xff1f; 为什么选择 Pinia&#xff1f; 基本使用 安装pinia 配置pinia 定义store 使用 持久化插件 什么是 Pinia&#xff1f; Pinia 是一个轻量级的状态管理库&#xff0c;专为 Vue 3 设计。它提供了类似 Vuex 的功能&#xff0c;但 API 更加简…

02 基本介绍及Pod基础排错

01 yaml文件里的字段错误 # 多打了一个i导致的报错 [rootmaster01 yaml]# cat 01-pod.yaml apiVersion: v1 kind: Pod metadata:name: likexy spec:contaiiners:- name: aaaimage: registry.cn-hangzhou.aliyuncs.com/yinzhengjie-k8s/apps:v1 [rootmaster01 yaml]# kubectl …

⼆叉搜索树详解

1. ⼆叉搜索树的概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树: • 若它的左⼦树不为空&#xff0c;则左⼦树上所有结点的值都⼩于等于根结点的值 • 若它的右⼦树不为空&#xff0c;则右⼦树上所有结点的值都⼤于等于根结…

如何使用通义灵码提高前端开发效率

工欲善其事&#xff0c;必先利其器。对于前端开发而言&#xff0c;使用VSCode已经能够极大地提高前端的开发效率了。但有了AI加持后&#xff0c;前端开发的效率又更上一层楼了&#xff01; 本文采用的AI是通义灵码插件提供的通义千问大模型&#xff0c;是目前AI性能榜第一梯队…

Android Studio Kotlin 中的方法添加灰色参数提示

在使用 Android Studio 时&#xff0c; 我发现使用 Java 编写方法后在调用方法时&#xff0c; 会自动显示灰色的参数。 但在 Kotlin 中没有显示&#xff0c; 于是找了各种方法最后找到了设置&#xff0c; 并且以本文章记录下来。 博主博客 https://blog.uso6.comhttps://blog.…

TCP协议简介

TCP 协议 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是互联网协议套件中的核心协议之一&#xff0c;位于传输层。它提供了一种可靠的、面向连接的、基于字节流的数据传输服务。TCP 的主要特点是确保数据在传输过程中不丢失、不重复&a…

Linux学习心得问题整理(二)

day05 Linux基础入门 Linux语法解析 如何理解ssh远程连接?如何使用ssh使用远程连接服务&#xff1f; ssh进也称远程服务终端&#xff0c;常见连接方式可以包括windows和Linux两种方式 首先咱们使用windows窗口进行连接&#xff0c;这里就采用xshell连接工具来给大家做演示吧…

SOC-ESP32S3部分:2-2-VSCode进行编译烧录

飞书文档https://x509p6c8to.feishu.cn/wiki/CTzVw8p4LiaetykurbTciA42nBf?fromScenespaceOverview 无论是使用Window搭建IDF开发环境&#xff0c;还是使用Linux Ubuntu搭建IDF开发环境&#xff0c;我们都建议使用VSCode进行代码编写和编译&#xff0c;VSCode界面友好&#x…

Python虚拟环境再PyCharm中自由切换使用方法

Python开发中的环境隔离是必不可少的步骤,通过使用虚拟环境可以有效地管理不同项目间的依赖,避免包冲突和环境污染。虚拟环境是Python官方提供的一种独立运行环境,每个项目可以拥有自己单独的环境,不同项目之间的环境互不影响。在日常开发中,结合PyCharm这样强大的IDE进行…

使用Mathematica绘制一类矩阵的特征值图像

学习过线性代数的&#xff0c;都知道&#xff1a;矩阵的特征值非常神秘&#xff0c;但却携带着矩阵的重要信息。 今天&#xff0c;我们将展示&#xff1a;一类矩阵&#xff0c;其特征值集体有着很好的分布特征。 modifiedroots[c_List] : Block[{a DiagonalMatrix[ConstantAr…

SpringBoot-6-在IDEA中配置SpringBoot的Web开发测试环境

文章目录 1 环境配置1.1 JDK1.2 Maven安装配置1.2.1 安装1.2.2 配置1.3 Tomcat1.4 IDEA项目配置1.4.1 配置maven1.4.2 配置File Encodings1.4.3 配置Java Compiler1.4.4 配置Tomcat插件2 Web开发环境2.1 项目的POM文件2.2 项目的主启动类2.3 打包为jar或war2.4 访问测试3 附录3…

基于springboot+vue的病例管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.3.9 系统展示 患者信息管理 医…

SpringBoot(三)--- 数据库基础

目录 前言 一、MySQL 1. 关系型数据库 2.数据模型 二、SQL语句 1.DDL语句 1.1 数据库操作 1.1.1 查询数据库 1.1.2 创建数据库 1.1.3 使用数据库 1.1.4 删除数据库 1.2 表操作 1.2.1 创建表 1.2.2 约束 1.2.3 数据类型 2.DML语句 2.1 增加&#xff08;insert&…

【漫话机器学习系列】268. K 折交叉验证(K-Fold Cross-Validation)

图解 K 折交叉验证&#xff08;K-Fold Cross-Validation&#xff09;| 原理 数学公式 实践应用 原图作者&#xff1a;Chris Albon&#xff0c;手绘风格清晰易懂&#xff0c;本文基于其图解做详细扩展&#xff0c;适用于机器学习、深度学习初学者及进阶者参考学习。 一、什么是…

【学习心得】Jupyter 如何在conda的base环境中其他虚拟环境内核

如果你在conda的base环境运行了jupyter lab打开了一个ipynb文本&#xff0c;此时选择的内核是base虚拟环境的Python内核&#xff0c;如果我想切换成其他conda虚拟环境来运行这个文件该怎么办&#xff1f;下面我们试着还原一下问题&#xff0c;并且解决问题。 【注】 这个问题出…

【Boost搜索引擎】构建Boost站内搜索引擎实践

目录 1. 搜索引擎的相关宏观原理 2. 正排索引 vs 倒排索引 - 搜索引擎具体原理 3. 编写数据去标签与数据清洗的模块 Parser 去标签 编写parser 用boost枚举文件名 解析html 提取title ​编辑 去标签 构建URL 将解析内容写入文件中 4. 编写建立索引的模块 Index 建…

Nginx配置记录访问信息

文章目录 方法一&#xff1a;使用Nginx原生配置记录访问信息方法二&#xff1a;使用Nginx_headers_more模块记录更加详细的信息 Nginx被广泛应用于各种场景如&#xff1a;Web服务器、反向代理服务器、负载均衡器、Web应用防火墙(WAF)等 在实际的产品开发中&#xff0c;无论是功…

HomeAssistant开源的智能家居docker快速部署实践笔记(CentOS7)

1. SGCC_Electricity 应用介绍 SGCC_Electricity 是一个用于将国家电网&#xff08;State Grid Corporation of China&#xff0c;简称 SGCC&#xff09;的电费和用电量数据接入 Home Assistant 的自定义集成组件。通过该应用&#xff0c;用户可以实时追踪家庭用电量情况&…

JAVA EE(进阶)_HTML

思如云烟&#xff0c;行若磐石。 ——陳長生. ❀主页&#xff1a;陳長生.-CSDN博客❀ &#x1f4d5;上一篇&#xff1a;JAVA EE&#xff08;进阶&#xff09;_进阶的开端-CSDN博客 1.HTML HTML&#xff08;HyperText Mark…

职坐标AIoT技能培训课程实战解析

职坐标AIoT技能培训课程以人工智能与物联网技术深度融合为核心&#xff0c;构建了“理论实战行业应用”三位一体的教学体系。课程体系覆盖Python编程基础、传感器数据采集、边缘计算开发、云端服务部署及智能硬件开发全链路&#xff0c;通过分层递进的知识模块帮助学员建立系统…