Semaphore源码分析

47 阅读2分钟

整体概念

  • 内部类Sync继承AQS,基于AQS实现锁的机制,通过state表示许可的数量
  • 支持公平锁FairSync和非公平锁NonfairSync的模式

有关AQS的原理参考juejin.cn/post/748158… ,本文涉及AQS的方法不再重复分析

内部类介绍

Sync

//继承AQS
abstract static class Sync extends AbstractQueuedSynchronizer

构造方法

Sync(int permits) {
    //设置state为许可值
    setState(permits);
}

NonfairSync

非公平模式

//继承Sync实现非公平锁
static final class NonfairSync extends Sync

构造方法

NonfairSync(int permits) {
    super(permits);
}

FairSync

公平模式

static final class FairSync extends Sync

构造方法

FairSync(int permits) {
    super(permits);
}

构造方法

public Semaphore(int permits) {
    //默认非公平模式
    sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
    //支持模式调整,fair 为true公平模式,否则非公平模式
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

核心方法

acquire(int permits) 获取许可

public void acquire(int permits) throws InterruptedException {
    //参数值校验
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireSharedInterruptibly(permits);
}

acquireSharedInterruptibly(int arg)

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (
    //尝试获取许可资格,小于0失败
    tryAcquireShared(arg) < 0)
        //AQS中的方法不在分析
        //加入同步队列等待再次获取资格
        doAcquireSharedInterruptibly(arg);
}

tryAcquireShared(int acquires)

protected int tryAcquireShared(int acquires) {
    return nonfairTryAcquireShared(acquires);
}

nonfairTryAcquireShared(int acquires)

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        //许可数量
        int available = getState();
        //减1
        int remaining = available - acquires;
        if (
        //小于0说明许可数量已经用完了
        remaining < 0 ||
            //否则尝试CAS设置
            compareAndSetState(available, remaining))
            //返回剩余许可数
            return remaining;
    }
}

release() 释放许可

public void release() {
   sync.releaseShared(1);
}

releaseShared(int arg)

public final boolean releaseShared(int arg) {
    if (
    //尝试释放资格
    tryReleaseShared(arg)) {
        //AQS中的方法不在具体分析
        //唤醒同步队列中没拿到许可资格的线程
        doReleaseShared();
        return true;
    }
    return false;
}

tryReleaseShared(int releases)

protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        //当前许可数量
        int current = getState();
         //归还数量
        //归还一个在之前的数量上加1
        int next = current + releases;
        //校验
        if (next < current) // overflow
            throw new Error("Maximum permit count exceeded");
        if (
        //CAS
        compareAndSetState(current, next))
            return true;
    }
}

Semaphore整体流程总结:

  1. Semaphore(int permits)构造许可数量,默认非公平模式;
  2. acquire(int permits)获取许可,成功则执行,失败加入同步队列阻塞;
  3. release()释放许可数量,循环执行直到成功释放,成功释放后唤醒同步队列节点,之前获取许可失败的也能继续执行了