Semaphore源码阅读
本人的源码阅读主要聚焦于类的使用场景,一般只在java层面进行分析,没有深入到一些native方法的实现。并且由于知识储备不完整,很可能出现疏漏甚至是谬误,欢迎指出共同学习
本文基于corretto-17.0.9源码,参考本文时请打开相应的源码对照,否则你会不知道我在说什么
简介#
semaphore翻译过来即信号量,对semaphore最直观的解释就是,信号量是一个令牌桶,如果桶里的令牌数>=线程想要获取的令牌数,那么线程就能获取到令牌,然后继续执行,否则就要阻塞等待其他线程将令牌放入桶里,直到桶里令牌数足够,非常简单。
不像JUC里的Lock,线程只能释放自己获得的锁,即Lock有owner的概念,不能随便释放其他人的锁。而semaphore中令牌没有owner的概念,任何线程都能随意往桶里放令牌。
代码分析#
成员变量#
public class Semaphore implements java.io.Serializable {
private final Sync sync;
}
成员变量非常简单只有一个,看到Sync就该知道这个是AQS了。信号量还支持fairness,因此Sync作为抽象基类,实现了NonFairSync和FairSync。
方法#
Sync#
Sync继承自AQS,state定义为桶中令牌数量。由于可能同时有多个线程获得令牌,自然需要重写AQS的两个方法:
- tryAcquireShared
- tryReleaseShared
在tryAcquire这里需要区分公平与否,在之前的文章说过,公平的tryAcquire通过检查是否有前驱等待者,即下面两个条件满足一个都属于有前驱等待者,那么就直接tryAcquire失败:
- 当前线程没进入阻塞队列,且队列不为空
- 当前线程已经在阻塞队列中,但前面有更靠近队头(等待时间更长)的线程
否则如果是非公平的,就直接尝试更改state即可。
abstract static class Sync extends AbstractQueuedSynchronizer {
// 初始化state为令牌数量
Sync(int permits) {
setState(permits);
}
final int getPermits() {
return getState();
}
// nonfair版本的tryAcquireShared,如果目前令牌足够,直接更改令牌数(state)即可
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
// 往桶里放令牌,直接更改state
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
// 忽略其他非核心方法
}
NonFairSync#
static final class NonfairSync extends Sync {
NonfairSync(int permits) {
super(permits);
}
// 非公平tryAcquire
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
FairSync#
static final class FairSync extends Sync {
private static final long serialVersionUID = 2014338818796000944L;
FairSync(int permits) {
super(permits);
}
// 公平tryAcquire
protected int tryAcquireShared(int acquires) {
for (;;) {
// 检查是否有阻塞更久的线程
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律