弱肉强食信号量 --Semaphore

一:风骚概述

前面介绍了计数器CountDownLatch与栅栏CyclicBarrier,本文介绍最后一个并发工具类Semaphore信号量。该工具类用于限流,有点类似于令牌桶。使用共享锁实现,线程争抢桶中令牌,成功则执行,失败则等待

二:初始化令牌

桶中令牌初始化数量在实例化对象时传入,使用AQS锁标记state维护保存。需要注意这个令牌数量并不是固定值,可以在程序运行过程中动态增长,这一点后续源码会介绍。构造函数有公平与非公平重载,类似于独占锁ReentrantLock,公平实现中需要判断获取令牌线程是否为等待队列第一个线程节点
在这里插入图片描述

三:非公平实现

本描述默认读者已经很熟悉AQS部分,不了解读者建议先行阅读独占锁ReentrantLock学习AQS相关知识点

3.1 tryAcquireShared

内部抽象类Sync实现非公平设计,用于NonFairSync中基本方法tryAcquireShare()实现调用。看逻辑其实很简单,判断锁标志属性state数量是否大于目前线程需要获取的令牌数量。大于则CAS更改state属性值,小于则返回执行doAcquireSharedInterruptibly()
在这里插入图片描述

3.2 doAcquireSharedInterruptibly

这块的逻辑与独占锁ReentrantLock实现基本一致,都是过程中尝试再次获取令牌。更改节点等待属性值并在parkAndCheckInterrupt()中依赖LockSupport的park()方法睡眠线程
在这里插入图片描述

四:公平实现

公平实现与非公平实现就一点区别,尝试获取令牌的时候是否需要判断为等待队列第一个线程节点,通过方法hasQueuedPredecessors()判断。这与ReentrantLock中又是保持一致
在这里插入图片描述

五:归还令牌

有借有还,再借不难。使用的令牌肯定是需要还回去,接下来就是重点描述令牌的动态增长问题。如下realse()归还令牌方法可以指定归还数量
在这里插入图片描述
方法tryReleaseShared()中变更state属性值用于记录当前令牌数量,但是注意这里并未校验线程前面获取的令牌数量,也就是说你随便还多少都行,这就是产生令牌动态增长的原因
在这里插入图片描述
唤醒操作在doReleaseShared()中进行,遍历等待列表通过LockSupport工具类调用unpark()方法唤醒线程。当然看这个方法就是死循环也就是唤醒所有等待队列线程节点,然后再争抢令牌的时候再判断令牌数量决定是否执行线程
在这里插入图片描述

六:系列重载

值得一提的是前面信号量获取令牌的acquire()方法为线程中断敏感实现,当然也针对这个问题提出了线程中断不敏感重载实现。与独占锁ReentrantLock类似,获取令牌也提供了系列限时等待、尝试获取等重载实现。具体代码细节可以自行查看源码,与acquire()实现差距不大
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值