Semaphore原理剖析

简介: Semaphore原理剖析

1. 简介


简单描述Semaphore 的功能,那就是信号量 Semaphore 是一个控制访问多个共享资源的计数器,和 CountDownLatch 一样,其本质上是一个“共享锁”


2. 实现原理


网络异常,图片无法展示
|


  • 在Semaphore声明阶段对许可量进行初始化,配置许可量数量permit
  • 调用acquire方法会获取permit,这里默认获取一个,也可以传入获取的许可量数量一次获取多个;当信号量数量为0时调用线程会进入阻塞等待状态;信号量的获取方法提供了公平锁非公平锁获取两种方式
  • 调用release方法会释放permit,将信号量归还以供其他线程获取


3. 源码结构


网络异常,图片无法展示
|


  • J.U.C包中的最核心部分就是AQS的实现,它是JDK并发工具的实现基石,Semaphore 是基于AQS进行实现的
  • acquire、release方法分别调用了AQS的tryAcquireShared、tryReleaseShared方法对AQS的共享变量state进行操作;基于自身Sync提供了FairSync公平锁NonFairSync非公平锁的实现
  • acquire方法获取许可量,支持单个或多个获取,即信号量递减;当许可量为0时,进行线程阻塞等待
  • release方法用来控制许可量,对其进行释放,即信号量增加


4. 源码剖析


4.1 acquire方法


网络异常,图片无法展示
|


  • 调用acquire() 方法,开始获取信号量许可
  • 该方法内部使用 AQS 的 acquireSharedInterruptibly(int arg) 方法
  • 在内部类提供了FairSync和NonFairSync两种实现重写 tryAcquireShared(int arg) 的方法,即公平锁非公平锁的实现
  • 通过AQS中的getState() 方法,获取同步状态,即信号量许可数
  • 如果计数器值等于 0,则会自旋,尝试一直去获取直到许可数大于0,即有可以允许的信号量为止


4.2 release方法


网络异常,图片无法展示
|


  • 调用release() 方法,来释放信号量,或者说是归还信号量,实际是将信号量增加,可以让其他线程有机会获取到共享变量进行执行
  • 内部调用AQS的releaseShared() 方法
  • Sync重写了tryReleaseShared() 方法,这里和CountDownLatch的实现类似
  • 释放锁,也就是操作计数器的过程,这里使用到了CAS(compareAndSetState)进行计数更新,若更新失败则进行自旋重试直到成功为止


5. 实战用例


汽车准乘人数有限,模拟两个旅行团乘客上车


/**

* created by guanjian on 2020/12/28 15:31

*/

public class SemaphoreTest {


   //模拟汽车准乘人数

   private final static Semaphore semaphore = new Semaphore(5);


   //A旅行团人数5人

   private final static int A_NUMS = 5;

   //B旅行团人数5人

   private final static int B_NUMS = 5;


   public static void main(String[] args) throws InterruptedException {

       //A旅行团上车

       new Thread(() -> {

           IntStream.range(0,A_NUMS).forEach(x->{

               try {

                   System.out.format("当前汽车准乘人数=%s \n", semaphore.availablePermits());

                   semaphore.acquireUninterruptibly();

                   System.out.println("A旅行团上车1人 \n");

                   Thread.sleep(new Random().nextInt(3000));

                   System.out.format("剩余汽车准乘人数=%s \n", semaphore.availablePermits());

               }catch (Exception e){

                   e.printStackTrace();

               }

           });

       }).start();


       //B旅行团上车

       new Thread(() -> {

           IntStream.range(0,B_NUMS).forEach(x->{

               try {

                   System.out.format("当前汽车准乘人数=%s \n", semaphore.availablePermits());

                   semaphore.acquireUninterruptibly();

                   System.out.println("B旅行团上车1人 \n");

                   Thread.sleep(new Random().nextInt(3000));

                   System.out.format("剩余汽车准乘人数=%s \n", semaphore.availablePermits());

               }catch (Exception e){

                   e.printStackTrace();

               }

           });

       }).start();

   }

}


6. 总结


  • 实现本质还是通过操作AQS的state实现多线程的通信交互
  • 相比CountDownLatch的实现,Semaphore可以对state进行数量的增加、减少的单个或多个操作
  • 获取共享变量的实现,即获取锁的实现提供了公平锁、非公平锁的实现,选择性更多
  • 释放锁即变更共享变量递增的实现,通过自旋锁和CAS配合完成,这与其他JUC并发工具如CountDownLatch类似


7. 参考


http://www.iocoder.cn/JUC/sike/Semaphore/

相关文章
|
存储 关系型数据库 MySQL
MYSQL 单表可以放多少数据是怎么计算出来的
MYSQL 单表可以放多少数据是怎么计算出来的
410 1
|
9月前
|
JSON API 开发者
速卖通获得AliExpress商品详情API接口文章
速卖通(AliExpress)是阿里巴巴旗下的全球跨境电商平台,提供便捷的在线购物渠道。为帮助开发者和商家高效管理商品信息,速卖通提供了商品详情API接口。本文介绍如何使用aliexpress.item_get API获取商品详情,包括获取API密钥、调用API接口及处理响应数据,帮助用户提升商品管理和营销效率。注意API调用限制和合法合规使用。
|
安全 网络协议 网络安全
端口转发:解锁网络访问的新维度
端口转发技术,简化网络数据流,用于家庭至企业服务器场景。它隐藏内部网络服务,提供远程访问、个人网站公开、NAT穿透及安全的VPN连接。设置涉及路由器管理界面,添加转发规则,但需注意安全风险,仅开放必要端口并加强内部安全措施。了解和善用端口转发,提升网络服务可达性与安全性。
706 5
|
缓存 监控 API
淘宝 API 接口使用的技术要点与注意事项
在数字化商业环境中,淘宝API为开发者提供了强大的工具,用于与淘宝平台交互,获取商品信息及处理交易等。本文总结了正确使用API的关键技术要点:注册认证、理解接口文档、遵守调用限制、确保参数准确性、保护数据安全、处理异常、性能优化、版本兼容、合规性及日志监控,帮助开发者实现高效、安全的程序开发。
|
存储 Java
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
264 4
|
存储 Kubernetes 安全
在k8S中,Secret 有哪些使用方式?
在k8S中,Secret 有哪些使用方式?
|
11月前
贪吃蛇游戏(代码篇)
贪吃蛇游戏(代码篇)
325 0
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点展示了如何使用 Kotlin 实现 AES-256 的加密和解密,提供了详细的代码示例。
284 2
|
存储 人工智能 自然语言处理
打造专业高效的AI客服:从基础准备到深度训练的全面指南
【7月更文第14天】在数字化转型的浪潮中,人工智能客服(AI Customer Service)已成为提升企业服务质量和效率的关键。一个训练有素的AI客服不仅能提供24/7不间断服务,还能精准理解客户需求,有效提升客户满意度。本文将深入探讨如何构建这样一个系统,包括必备的硬性条件、训练流程及成本考量,辅以实际代码示例,为您的企业开启智能客服新时代。
3057 1
|
缓存 前端开发 JavaScript
年度代码翻车现场 |前端代码评审问题总结
代码评审于技术团队的工程师文化建设非常有意义,它是形成团队统一代码风格最有效的方式,作者把自己团队在一年的CR中常见的那些小问题做了一些梳理,希望能对大家起到一点小帮助。
220250 8