Semaphore-信号量的实现分析

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 可以用来实现限流的作用。

猜你喜欢

转载自juejin.im/post/5c1c770d5188252e8966ee1a