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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章