Semaphore源码分析

Semaphore通常用于在程序中做限流使用,控制一段程序同时只能有n个线程同时访问。
既然是同时有多个线程能同时访问,那Semaphore是用的肯定就是共享锁。其原理就是有线程获取了锁,就对state减,释放锁后就对state加。state小于0的时候,就对线程阻塞。一旦释放了锁,就唤醒等待线程。

Semaphore是通过共享锁实现的,如果对ReentrantReadWriteLock不熟悉的,请先看ReentrantReadWriteLock源码分析。弄明白了共享锁,理解Semaphore就很简单了。

Semaphore创建

//默认使用的是非公平锁
public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}
//传入的permits保存在state中
Sync(int permits) {
    setState(permits);
}

semaphore.acquire

public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //修改state的值,返回值为还剩余的state,如果小于0,说明state已经用完,则需要将线程挂起
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
//tryAcquireShared非公平锁的实现。
//非公平锁允许后来的线程直接获取锁。公平锁的实现,判断如果等待队列中有等待线程,就不允许后来的线程插队获取锁。
final int nonfairTryAcquireShared(int acquires) {
	//每来一个线程,就将state的值做减法,返回值为还剩余的数量
	//如果CAS失败了,说明有其他线程正在抢占,则继续下一次的循环再次尝试
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}
//将线程封装为Node节点并挂起
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                	//获取锁之后,会链式继续唤醒下一个节点
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

semaphore.release

public final boolean releaseShared(int arg) {
	//如果释放锁成功了,就唤醒线程
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
protected final boolean tryReleaseShared(int releases) {
	//这里释放锁,和获取锁的逻辑是相反的,这里对state最加法,成功了就返回true,就会唤醒等地啊队列中的线程。
    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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章