semaphore源码解析:信号量到底是个啥?

一、概述

semaphore,字面意思是信号量,官方的如下:

 
 * A counting semaphore.  Conceptually, a semaphore maintains a set of
 * permits.  Each {
   
   @link #acquire} blocks if necessary until a permit is
 * available, and then takes it.  Each {
   
   @link #release} adds a permit,
 * potentially releasing a blocking acquirer.
 * However, no actual permit objects are used; the {
   
   @code Semaphore} just
 * keeps a count of the number available and acts accordingly.
 *
 * Semaphores are often used to restrict the number of threads than can
 * access some (physical or logical) resource.

是不是感觉,这解释有点不接地气,又是信号量,又是许可啥的。

下面简单用一个场景来解释,一下子你就可以明白了。


比如说,某个银行大堂,只有三个办事窗口。

这时来了一堆人办业务,都被门口保安给拦住了。

保安说三个窗口,只让三个人进大堂。其它人只能在外边等着。

这时有个人办完业务,出来了。保安这时就放一个人进去。

总之,大堂里,最多只有三个人办理业务。

semaphore 的功能,和这个保安差不多,只让三个人进去。

其实 Semaphore 是 AQS 框架实现的,和 ReentrantLock 实现原理相似。

之前写过一篇《ReentrantLock 的源码分析》,如果看过,这篇就不用细看了。

二、示例代码

下面的代码,创建了 10 个线程,模拟 10 个线程抢 3 个许可的场景。


 public static void main(String[] args) throws Exception {
   
   
     Semaphore semaphore = new Semaphore(3,false);  // 创建三个许可
     CountDownLatch downLatch = new CountDownLatch(1);
     for(int i = 0; i < 10; i++){
   
   
         new Thread(() -> {
   
   
             try {
   
   
                 downLatch.await();
                 semaphore.acquire();  // 获取许可
                 int randomSecond = RandomUtil.randomInt(1, 10);
                 Thread.sleep(randomSecond);
                 log.info("当前线程名:{},占用窗口时间:{},准备出来了。", Thread.currentThread().getName(),randomSecond);
                 semaphore.release(); // 解放许可
             } catch (InterruptedException e) {
   
   
                 e.printStackTrace();
             }
         }).start();
     }
     Thread.sleep(2000);
     log.info("-------10个线程创建完毕,准备开始抢位置了……");
     downLatch.countDown();

简单解释下代码

Semaphore semaphore = new Semaphore(3,false); 

这句和意思,是创建3个许可,即上面例子中,保安说,只有三个窗口,只让三个人进去。

另: 这里参数 false,影响不大,是公平模式还是非公平模式,后面再具体说。

semaphore.acquire(); 这句指使用一个许可。即上面例子中,某人占用了一个办事窗口。

如果执行这个方法时,许可用完了,即上面例子中,三个窗口都有人,那代码阻塞在这一行。

semaphore.release(); 指许可使用完了,归还许可。即上面例子中,一个人办完业务,出来了。

执行这个方法时,会唤醒被阻塞的线程,使其尝试去申请许可。

前面说过 Semaphore 是 AQS 框架的,结合下面的图,说说 Semaphore的实现原理。

new Semaphore(3,false),即 state 设置为3,

semaphore.acquire(); 有两种情况,

  1. state 大于 0,将 state 的值减 1,结束。(上面例子中,有空窗口,即有许可)
  2. state 小于等于0,进入队列中,等待被唤醒。(上面例子中,没有空窗口,即无许可)

semaphore.release(); 将 state 值加1,并唤醒队列中第一个节点,让其去获取许可。

在这里插入图片描述
原理就这么点,也不复杂,是不是感觉,和 ReentrantLock 差不多呢?

确实差不多,都是有线程竞争时排队,都会限制访问某资源。

ReentrantLock 可以解决高并发问题,Semaphore 能解决高并发问题么?

不一定。new Semaphore(1,false),当把这个参数设置为 1时,跟 ReentrantLock 就一模一样了。

其它情况下,就不一定了。

比如说上面银行大堂的例子,保安是只让三个人进来办业务,

假如第一个窗口,银行前台妹子特别漂亮。

这三个人都抢着去第一个窗口,保安不干涉这个。

即,Semaphore 可以限制资源访问,但不保证原子性。

三、源码解析

源码部分是比较枯燥的,上面解释的差不多可以应对面试了。下面的源码解释可以不用看哈。

  1. 创建实例

Semaphore 类中有个内部类,Sync,该类继承了 AQS

另外公平模式与非公平模式,各自是一个内部类,都继承了 Sync

    abstract 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值