一、Semaphore 概述
1.1 基本概念
Semaphore(信号量)是 Java 并发包 (java.util.concurrent) 中一个重要的同步工具类,用于控制同时访问特定资源的线程数量。它通过维护一组"许可"(permits)来实现资源访问的限制,线程必须获取许可才能访问资源,使用完毕后释放许可供其他线程使用。
1.2 核心特性
- 资源访问控制:限制同时访问某资源的线程数量
- 公平性选择:支持公平和非公平两种模式
- 许可管理:可动态调整许可数量
- 灵活获取:支持阻塞和非阻塞获取方式
- 可中断操作:支持获取许可时的中断响应
二、Semaphore 实现原理
2.1 底层架构
Semaphore 基于 AQS (AbstractQueuedSynchronizer) 实现:
public class Semaphore implements java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
// 构造方法
Sync(int permits) {
setState(permits);
}
// 非公平获取
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
// 释放许可
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;
}
}
}
// 非公平版本
static final class NonfairSync extends Sync {
// 实现略...
}
// 公平版本
static final class FairSync extends Sync {
// 实现略...
}
}
2.2 工作流程
- 初始化:创建 Semaphore 并指定许可数量
- 获取许可:线程调用 acquire() 方法获取许可(减少许可数)
- 资源访问:获得许可后访问受限资源
- 释放许可:线程调用 release() 方法释放许可(增加许可数)
- 阻塞/唤醒:当无许可可用时,线程阻塞;许可释放时唤醒等待线程
三、Semaphore 核心方法详解
3.1 构造方法
// 创建具有给定许可数的非公平 Semaphore
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
// 创建具有给定许可数和公平性设置的 Semaphore
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
3.2 获取许可方法
// 获取一个许可,阻塞直到可用或线程被中断
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 获取一个许可,阻塞直到可用(不响应中断)
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
// 尝试获取许可,立即返回获取结果
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
// 尝试获取许可,带超时等待
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
// 获取多个许可
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
3.3 释放许可方法
// 释放一个许可
public void release() {
sync.releaseShared(1);
}
// 释放多个许可
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
3.4 其他重要方法
// 返回当前可用许可数
public int availablePermits() {
return sync.getPermits();
}
// 获取并返回所有立即可用的许可
public int drainPermits() {
return sync.drainPermits();
}
// 减少许可数(缩减)
protected void reducePermits(int reduction) {
if (reduction < 0)

最低0.47元/天 解锁文章
3035

被折叠的 条评论
为什么被折叠?



