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/

相关文章
|
2月前
|
Java
JAVA并发编程系列(7)Semaphore信号量剖析
腾讯T2面试,要求在3分钟内用不超过20行代码模拟地铁安检进站过程。题目设定10个安检口,100人排队,每人安检需5秒。实际中,这种题目主要考察并发编程能力,特别是多个线程如何共享有限资源。今天我们使用信号量(Semaphore)实现,限制同时进站的人数,并通过信号量控制排队和进站流程。并详细剖析信号量核心原理和源码。
|
3月前
|
Java 数据库 开发者
CountDownLatch、CyclicBarrier和Semaphore原理和区别
CountDownLatch、CyclicBarrier和Semaphore
|
3月前
Semaphore原理
文章概述了Semaphore的工作原理及其使用场景:Semaphore是一种有效的限流工具,可以用来控制同一时刻访问共享资源的线程数量。它适用于需要对资源访问进行限流的场景,以避免资源过载或实现公平的资源分配。
Semaphore原理
|
6月前
|
Java 数据库
Semaphore(信号量)源码解读与使用
Semaphore(信号量)源码解读与使用
|
6月前
|
算法 Java 调度
Semaphore实现原理全面解析
Semaphore(信号量)是一个同步工具类,通过Semaphore可以控制同时访问共享资源的线程个数。
|
6月前
多线程并发之Semaphore(信号量)使用详解
多线程并发之Semaphore(信号量)使用详解
2085 0
Semaphore使用及原理解读
Semaphore使用及原理解读
Semaphore使用及原理解读
|
Java
Java多线程:Semaphore
Java多线程:Semaphore
115 0
并发编程之Semaphore信号量
`Semaphore` 翻译过来就是信号量, 其根本原理就是基于 `CAS` 共享锁的一种实现。举一个例子。 假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。
165 0
Semaphore 信号量源码分析
Semaphore 信号量源码分析
Semaphore 信号量源码分析