今天我们来聊一聊Java中的Semaphore

news2025/4/13 16:03:34

写在开头

在上几天写《基于AQS手写一个同步器》时,很多同学留言说里面提到的Semaphore,讲得太笼统了,今天趁着周末有空,咱们就一起详细的学习和梳理一把 Semaphore

什么是Semaphore?

在前面我们讲过的synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,而Semaphore(信号量)可以用来控制同时访问特定资源的线程数量,多线程同时操作共享资源,仍然存在着线程不安全问题,要想多线程安全,理应结合锁进一步保障。

Semaphore的主要结构

我们跟进信号量的源码中浏览一圈,发现其实它内部主要的方法就2个:

// 初始共享资源数量
final Semaphore semaphore = new Semaphore(5);
// 获取1个许可
semaphore.acquire();
// 释放1个许可
semaphore.release();

① acquire():获取许可

跟进这个方法后,我们会发现其内部调用了AQS的一个final 方法acquireSharedInterruptibly(),这个方法中又调用了tryAcquireShared(arg)方法,作为AQS中的钩子方法,这个方法的实现在Semaphore的两个静态内部类 FairSync(公平模式)NonfairSync(非公平模式) 中。

【源码解析1】

/**
 *  获取1个许可证
 */
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}
/**
 * 共享模式下获取许可证,获取成功则返回,失败则加入阻塞队列,挂起线程
 */
public final void acquireSharedInterruptibly(int arg)
    throws InterruptedException {
    if (Thread.interrupted())
      throw new InterruptedException();
        // 尝试获取许可证,arg为获取许可证个数,当可用许可证数减当前获取的许可证数结果小于0,则创建一个节点加入阻塞队列,挂起当前线程。
    if (tryAcquireShared(arg) < 0)
      doAcquireSharedInterruptibly(arg);
}

继续跟入tryAcquireShared(arg)方法,虽然它在AQS中,但它作为钩子方法,最终的实现则回到了Semaphore的内部类中。

钩子方法: 一种抽象类中的方法,一般使用 protected 关键字修饰,可以给与默认实现,空方法居多,其内容逻辑由子类实现,为什么不适用抽象方法呢?因为,抽象方法需要子类全部实现,增加大量代码冗余!

在这里插入图片描述

【扩展】

  1. FairSync(公平模式): 调用 acquire() 方法的顺序就是获取许可证的顺序,遵循 FIFO;
  2. NonfairSync(非公平模式): 抢占式的,在构造方法中通过一个布尔值fair来配置公平与非公平,默认为非公平模式。

② release():释放许可

同样跟入这个方法,里面用了AQS的releaseShared(),而在这个方法内也毫无疑问的用了tryReleaseShared(int arg)这个钩子方法,原理同上,不再冗释,需要注意的是释放共享锁的同时也会唤醒同步队列中的一个线程。

【源码解析2】

// 释放一个许可证
public void release() {
    sync.releaseShared(1);
}

// 释放共享锁,同时会唤醒同步队列中的一个线程。
public final boolean releaseShared(int arg) {
    //释放共享锁
    if (tryReleaseShared(arg)) {
      //唤醒同步队列中的一个线程
      doReleaseShared();
      return true;
    }
    return false;
}

Semaphore的使用

OK,讲到这里,把信号量中主要的方法解释完了,我们来写一个小demo感受一下它的使用:

【测试用例1】

public class Test {
    private final Semaphore semaphore;

    /*构造一个令牌*/
    public Test(int acq){
        this.semaphore= new Semaphore(acq);
    }
    public void useSemaphore(){
        try {
            semaphore.acquire();
            // 使用资源
            System.out.println("资源开始使用了 " + Thread.currentThread().getName());
            Thread.sleep(1000); // 模拟资源使用时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
            System.out.println("资源释放了 " + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        Test test = new Test(3);
        for (int i = 0; i < 5; i++) {
            new Thread(test::useSemaphore).start();
        }
    }
}

输出:

资源开始使用了 Thread-0
资源开始使用了 Thread-1
资源开始使用了 Thread-3
资源释放了 Thread-0
资源开始使用了 Thread-2
资源开始使用了 Thread-4
资源释放了 Thread-1
资源释放了 Thread-3
资源释放了 Thread-4
资源释放了 Thread-2

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

在这里插入图片描述
如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

在这里插入图片描述

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

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

相关文章

【计算机毕业设计】人事管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

【刷题】代码随想录算法训练营第十一天|20、有效的括号,1047、删除字符中的所有相邻重复项,150、逆波兰表达式求值

目录 20、有效的括号1047、删除字符中的所有相邻重复项150、逆波兰表达式求值 20、有效的括号 讲解&#xff1a;https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html 括号匹配是使用栈解决的经典问题。 三种不匹配&#xff1a;第一种是缺少匹…

Axure RP中的相关概念及高保真原型构建方法

1 Axure RP中概念介绍 对于构建高保真原型来说&#xff0c;需要知道事件&#xff08;Event&#xff09;、Case、Action等概念。Axure RP中给出这些概念&#xff0c;是为了方便原型的构建&#xff0c;尤其是高保真原型的构建。 事件&#xff08;Event&#xff09;是附着于控件…

.vue文件引入路径正确,但报错

问题描述 使用Vue挂载组件时&#xff0c;导入路径正确&#xff0c;但是一直提示 Already included file name ‘绝对路径/index.vue’ differs from file name ‘绝对路径/Index. vue’ only in casing. The file is in the program because: Imported via ‘./components/ind…

Ubuntu,Kylin环境使用clock()函数设置延迟

一、Ubuntu操作系统中&#xff0c;直接在main中测试clock()设置延迟功能 代码描述&#xff1a;直接在main中使用clock()函数设置200ms延迟。 代码输出&#xff1a; 实现了200ms的延迟。 #include <time.h> #include <sys/time.h> #include <stdio.h> #inc…

HarmonyOS实战开发-自定义通知角标、如何设定应用的桌面图标角标的功能。

介绍 本示例主要展示了设定应用的桌面图标角标的功能&#xff0c;使用ohos.notificationManager 接口&#xff0c;进行桌面角标的设置&#xff0c;通知的发送&#xff0c;获取等。 效果预览 使用说明 在使用本应用时&#xff0c;需安装并启动仿桌面应用&#xff1b;在主界面…

微信小程序报错——“errno“: 600001, “errMsg“: “request:fail -2:net::ERR_FAILED“

bug现象 微信小程序体验版和真机调试 进入小程序的时候接口就出现了这个报错 "errno": 600001, "errMsg": "request:fail -2:net::ERR_FAILED" 排查 检查是证书过期还是证书链不完整 证书的信任链完整问题&#xff0c;可以在 亚数信息-SSL/TLS安…

Leetcode:283.移动零

题目要求 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0…

8、【构造者模式】适合于需要创建复杂对象的场景

你好&#xff0c;我是程序员。 今天我们来学习23种设计模式中的建造者模式。构造者模式是什么&#xff1f;有什么优缺点&#xff1f;使用场景&#xff0c;与工厂模式有什么区别&#xff1f;简单代码实现。 一、是什么&#xff1f; 建造者模式&#xff08;Builder Pattern&…

MySQL:MySQL的查询(上)

文章目录 MySQL的增加单行数据插入多行数据插入插入否则更新替换 MySQL的查询select列where语句 本篇开始总结的是MySQL当中的基本查询语句 对于数据库的查询&#xff0c;无非大致就是增删查改&#xff0c;因此对于这些内容进行一一解释&#xff1a; MySQL的增加 单行数据插…

鸿铭网创88计第49计:2024挂机托管项目, 单号躺赚4000+,无需发作品

项目概述&#xff1a; 这个副业项目极为适合忙碌却希望额外赚钱的伙伴们。核心是与平台合作&#xff0c;提供快手账号用于发布视频&#xff0c;视频中会嵌入推广链接。当有用户通过这些链接下载应用时&#xff0c;我们就能获得拉新佣金。 项目 地 址 &#xff1a; laoa1.cn/…

Json和Qt中Json的使用学习笔记

视频链接 https://www.bilibili.com/video/BV1yf4y1A7ek/?p2&spm_id_frompageDriver&vd_sourcefa4ef8f26ae084f9b5f70a5f87e9e41b Json JSON是在网络传输中常用的数据格式&#xff0c;能将不同类型的数据统一起来&#xff0c;我们在发送数据前将不同类型的数据存入到…

关于Git的一些基础用法

关于Git的一些基础用法 1. 前言2. 使用GitHub/gitee创建项目2.1 创建账号2.2 创建项目2.3 下载仓库到本地2.4 提交代码到远端仓库2.5 查看日志2.6 同步远端仓库和本地仓库 1. 前言 首先说一个冷知识&#xff08;好像也不是很冷&#xff09;&#xff0c;Linux和git的创始人是同…

c语言多功能计算软件170

定制魏&#xff1a;QTWZPW&#xff0c;获取更多源码等 目录 题目 要求 主要代码片段 题目 设计一个计算器软件&#xff0c;具备如下功能提示界面。 要求 设计出界面&#xff0c;注意界面名称最后为自己的姓名&#xff1b;&#xff08;20分&#xff09;能够实现加、减、乘、…

BoostCompass(建立正排索引和倒排索引模块)

阅读导航 一、模块概述二、编写正排索引和倒排索引模块✅安装 jsoncpp✅Jieba分词库的安装1. 代码基本框架2. 正排索引的建立3. 倒排索引的建立 三、整体代码⭕index.hpp 一、模块概述 这个模块我们定义了一个名为Index的C类&#xff0c;用于构建和维护一个文档索引系统。该系…

AI python

AI python 软件方面程序上的人工智能&#xff0c;和物理那种能跑机器人没关系

emmet语法---快速生成css样式

前言 本文是对emmet语法生成css样式的整理&#xff0c;emmet语法就相当于快捷键一样&#xff0c;只需要我们输入简单的缩写&#xff0c;然后按下tab键即可生成麻烦的css代码。 emmet语法生成css代码 其实&#xff0c;特别简单。比html还要简单。 先上案例&#xff1a; 我们输…

ControllerAdvice用法

ControllerAdvice用法 ControllerAdvice是一个组件注解&#xff0c;它允许你在一个地方处理整个应用程序控制器的异常、绑定数据和预处理请求。这意味着你不需要在每个控制器中重复相同的异常处理代码&#xff0c;从而使得代码更加简洁、易于管理。 主要特性 全局异常处理&a…

Python单元测试框架—pytest常用测试报告类型

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 先前博客有介绍pytest测试框架的安装及使用&#xff0c;现在来聊…

Stacked Hourglass Networks for Human Pose Estimation 用于人体姿态估计的堆叠沙漏网络

Stacked Hourglass Networks for Human Pose Estimation 用于人体姿态估计的堆叠沙漏网络 这是一篇关于人体姿态估计的研究论文&#xff0c;标题为“Stacked Hourglass Networks for Human Pose Estimation”&#xff0c;作者是 Alejandro Newell, Kaiyu Yang, 和 Jia Deng&a…