Semaphore源码剖析
Semaphore源码剖析
Semaphore从英⽂单词上翻译是:信号量,可以理解 他是⼀个 许可证。只有获取到 许可证 的线程,才能执⾏相应逻辑,同时拿⾛ 许可证,⽽那些没有获取到的线程 只能等待。当持有 许可证 的线程 执⾏完成 后,需要 归还 许可证, 下⼀个线程 才可以 获取 许可证 执⾏相应逻辑。
测试案例:
public class SemaphoreDemo {
public static void main(String[] args) {
SemaphoreDemo demo = new SemaphoreDemo();
demo.test();
}
private void test() {
// 停车场同时容纳的车辆 5
Semaphore semaphore = new Semaphore(5);
List<Thread> threadList = new ArrayList<>();
// 模拟 8 辆车进入停车场
for (int i = 0; i < 8; i++) {
threadList.add(new Thread(() -> this.park(semaphore)));
}
threadList.forEach(Thread::start);
}
private void park(Semaphore semaphore) {
try {
Random random = new Random();
int seconds = random.nextInt(4) + 2;
System.out.println(Thread.currentThread().getName() + " --> 来到停车场");
if (semaphore.availablePermits() == 0) {
System.err.println(Thread.currentThread().getName() + " --> 车位不足,请耐心等待");
}
semaphore.acquire();// 获取令牌尝试进入停车场
System.out.println(Thread.currentThread().getName() + " --> 成功进入停车场 停留时间 [" + seconds + "] 秒");
Thread.sleep(seconds * 1000);
System.out.println(Thread.currentThread().getName() + " --> 驶出停车场");
semaphore.release();//释放令牌,腾出停车场车位
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
Thread-3 --> 来到停车场
Thread-4 --> 来到停车场
Thread-0 --> 来到停车场
Thread-2 --> 来到停车场
Thread-5 --> 来到停车场
Thread-1 --> 来到停车场
Thread-7 --> 来到停车场
Thread-6 --> 来到停车场
Thread-3 --> 成功进入停车场 停留时间 [2] 秒
Thread-7 --> 成功进入停车场 停留时间 [3] 秒
Thread-4 --> 成功进入停车场 停留时间 [2] 秒
Thread-1 --> 成功进入停车场 停留时间 [4] 秒
Thread-2 --> 成功进入停车场 停留时间 [4] 秒
Thread-6 --> 车位不足,请耐心等待
Thread-4 --> 驶出停车场
Thread-3 --> 驶出停车场
Thread-5 --> 成功进入停车场 停留时间 [5] 秒
Thread-6 --> 成功进入停车场 停留时间 [2] 秒
Thread-7 --> 驶出停车场
Thread-0 --> 成功进入停车场 停留时间 [2] 秒
Thread-2 --> 驶出停车场
Thread-6 --> 驶出停车场
Thread-1 --> 驶出停车场
Thread-0 --> 驶出停车场
Thread-5 --> 驶出停车场
常用方法源码剖析:
public class Semaphore implements java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
.....
}
// permits:表示允许同时执行任务的线程个数,
// 底层其实是给aqs的state变量进行赋值
public Semaphore(int permits) {
// 默认使用非公平锁
sync = new NonfairSync(permits);
}
// 同上,fair=true时,使用公平锁
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
// 查看是否有可用的令牌
public int availablePermits() {
return sync.getPermits();// 底层就是直接获取的aqs的state的值
}
// 获取令牌
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 见读写锁该方法的解析
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
// 公平锁实现
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;
}
}
// 非公平锁实现
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
// 上来就直接开干
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
// 释放令牌
public void release() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
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;
}
}
}
总结:Semaphore底层其实还是基于AQS的state变量来进行操作的。