Semaphore
Semaphore 信号量:可以用来控制同时访问特定资源的线程数量;通过协调各个线程以保证合理的使用公共资源
构造
// permits 设置许可证的数量
public Semaphore(int permits) {
// 默认非公平
sync = new NonfairSync(permits);
}
// permits 设置许可数量
// fair 设置是否采用公平模式
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
非公平模式
acquire()
获取许可。只有当获取到可用的许可,或者当前线程被中断;否则该线程被阻塞
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
默认会调用 NonfairSync 下的 tryAcquireShared 方法,继续调用父类的 nonfairTryAcquireShared 方法
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
// 获取当前 state 值
// 也即是当前可用的许可数
int available = getState();
// 当前可用许可数减去尝试获取许可的数
// 得到剩余许可数
int remaining = available - acquires;
// remaining < 0 说明当前可用许可数小于尝试获取许可数,也即是获取同步状态失败 直接返回 remaining, 退出循环 当前线程会被添加到同步队列中
// remaining > 0 说明当前可用许可数大于尝试获取许可数,
// 则执行 compareAndSetState 更新 state , 若更新成功则返回 退出循环 当前线程获取到许可
// 若 compareAndSetState 更新失败,说明有其他线程获取到许可,则继续轮询
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
release
释放许可
public void release() {
sync.releaseShared(1);
}
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");
// 更新 state 值, 更新成功则返回 true 退出循环;并唤醒同步队列上阻塞的线程
// 更新 state 值失败,说明有其他线程获取许可或释放了许可,则继续轮询
if (compareAndSetState(current, next))
return true;
}
}
公平模式
acquire
公平模式下获取许可
protected int tryAcquireShared(int acquires) {
for (;;) {
// 判断同步队列上是否有阻塞的线程
// 若有的话,返回 -1 表示获取许可失败 退出循环加入同步队列中
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
从上述代码中可以看到,公平模式下获取许可和非公平模式下基本类似,只是为了保证 FIFO ,添加了 hasQueuedPredecessors 判断限制。
release
公平模式下与非公平模式一样
小结
Semaphore 可以用来实现限流的作用。
最后,如果你跟我一样都喜欢java,也在学习java的道路上奔跑,欢迎你添加 V X sweetbest130 每天都会分享java最新业内资料,共同交流学习,让学习变(编)成(程)一种习惯!