Java 併發程式設計(十五) -- Semaphore原始碼分析

我很醜發表於2020-03-16

1. 類的定義

public class Semaphore implements java.io.Serializable 
複製程式碼

2. 欄位屬性

//序列化版本號
private static final long serialVersionUID = -3222578661600680210L;
//同步器,AbstractQueuedSynchronizer的子類
private final Sync sync;
複製程式碼

從欄位屬性中可以看出

  • Semaphore的所有操作都是使用內部類Sync物件進行操作的

3. 構造方法

//傳入訊號數
public Semaphore(int permits) {
    	//預設使用非公平鎖
        sync = new NonfairSync(permits);
    }
//傳入訊號數和鎖的型別
public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
複製程式碼

從構造方法中可以看出

  • 構造方法只做了一件事:初始化sync物件

4.方法

acquire 方法

//可中斷的獲取訊號量
public void acquire() throws InterruptedException {
    	//呼叫sync的acquireSharedInterruptibly方法
        sync.acquireSharedInterruptibly(1);
    }

//獲取指定數量的訊號量
public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
    	//呼叫sync的acquireSharedInterruptibly方法
        sync.acquireSharedInterruptibly(permits);
    }
複製程式碼

acquireUninterruptibly 方法

//不可中斷的獲取訊號量
public void acquireUninterruptibly() {
    	//呼叫sync的acquireShared方法
        sync.acquireShared(1);
    }
//不可中斷的獲取指定數量的訊號量
public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }
複製程式碼

tryAcquire 方法

//嘗試獲取訊號量
public boolean tryAcquire() {
    	//呼叫sync的nonfairTryAcquireShared方法
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

//嘗試獲取指定數量的訊號量
public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
    	//嘗試獲取指定數量的訊號量
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

//設定超時時間的嘗試獲取訊號量
public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
    	//呼叫sync的tryAcquireSharedNanos方法
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

//設定超時時間的嘗試獲取指定數量的訊號量
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
    	//呼叫sync的tryAcquireSharedNanos方法
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }
複製程式碼

release 方法

//釋放一個訊號量
public void release() {
    	//呼叫sync的releaseShared方法
        sync.releaseShared(1);
    }
//釋放指定數量的訊號量
public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }
複製程式碼

availablePermits 方法

//獲取當前可用的通道數
public int availablePermits() {
        return sync.getPermits();
    }
複製程式碼

drainPermits 方法

//獲取立即可用的通道數
public int drainPermits() {
        return sync.drainPermits();
    }
複製程式碼

reducePermits 方法

//減少訊號數
protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();
        sync.reducePermits(reduction);
    }
複製程式碼

isFair 方法

//獲取鎖的型別, true 公平鎖, false 非公平鎖
public boolean isFair() {
        return sync instanceof FairSync;
    }
複製程式碼

hasQueuedThreads 方法

//佇列中是否有正在等訊號的執行緒
public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
複製程式碼

getQueueLength 方法

//獲取佇列中等待訊號的執行緒數
public final int getQueueLength() {
        return sync.getQueueLength();
    }
複製程式碼

getQueuedThreads 方法

//獲取佇列中的執行緒,以集合的方式返回
protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }
複製程式碼

5. 內部類Sync

1. 類的定義

abstract static class Sync extends AbstractQueuedSynchronizer
複製程式碼

從類的定義中可以看出

  • Sync是一個抽象的靜態內部類,使用模板方法的設計模式讓子類繼承
  • Sync繼承AbstractQueuedSynchronizer類

2. 欄位屬性

//序列化版本號
private static final long serialVersionUID = 1192457210091910933L;
複製程式碼

3. 構造方法

//傳入的訊號數就是AQS中的state
Sync(int permits) {
            setState(permits);
        }

複製程式碼

4. 方法

getPermits 方法
//獲取訊號數
final int getPermits() {
    		//實質上就是獲取state的值
            return getState();
        }

複製程式碼
nonfairTryAcquireShared 方法
//非公平方式獲取共享鎖,返回剩餘可用訊號數
final int nonfairTryAcquireShared(int acquires) {
    		//for無限迴圈,自旋CAS
            for (;;) {
                //獲取當前的state
                int available = getState();
                //可用訊號-獲取數量=剩餘可用數量
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

複製程式碼
tryReleaseShared 方法
//嘗試釋放共享鎖
protected final boolean tryReleaseShared(int releases) {
    		//for無限迴圈,自旋CAS
            for (;;) {
                //獲取當前的state
                int current = getState();
                //可用訊號+釋放數量=新的可用數量
                int next = current + releases;
                if (next < current) // overflow
                    //releases小於0 丟擲異常
                    throw new Error("Maximum permit count exceeded");
                //CAS,設定新值
                if (compareAndSetState(current, next))
                    return true;
            }
        }

複製程式碼
reducePermits 方法
//減少訊號數量
final void reducePermits(int reductions) {
    		//for無限迴圈,自旋CAS
            for (;;) {
                //獲取當前的state
                int current = getState();
                //可用訊號-減少的數量=新的可用數量
                int next = current - reductions;
                if (next > current) // underflow
                    //reductions小於0 丟擲異常
                    throw new Error("Permit count underflow");
                //CAS,設定新值
                if (compareAndSetState(current, next))
                    return;
            }
        }

複製程式碼
drainPermits 方法
//清空訊號
final int drainPermits() {
    		//CAS 自旋把state置為0
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }

複製程式碼

6. 內部類 NonfairSync

1. 類的定義

static final class NonfairSync extends Sync

複製程式碼

從類的定義可以看出

  • NonfairSync是Sync的子類

2. 欄位屬性

//序列化版本號
private static final long serialVersionUID = -2694183684443567898L;

複製程式碼

3. 構造方法

//設定state
NonfairSync(int permits) {
            super(permits);
        }

複製程式碼

4. 方法

tryAcquireShared 方法
//嘗試獲取共享鎖
protected int tryAcquireShared(int acquires) {
    		//呼叫父類的方法nonfairTryAcquireShared,直接搶鎖
            return nonfairTryAcquireShared(acquires);
        }

複製程式碼

7. 內部類FairSync

1. 類的定義

 static final class FairSync extends Sync

複製程式碼

從類的定義中可以看出

  • FairSync繼承Sync類

2. 欄位屬性

//序列化版本號
private static final long serialVersionUID = 2014338818796000944L;

複製程式碼

3. 構造方法

//設定state
FairSync(int permits) {
            super(permits);
        }

複製程式碼

方法

tryAcquireShared 方法
//嘗試獲取共享鎖
protected int tryAcquireShared(int acquires) {
            for (;;) {
                //先看佇列中是否有執行緒排隊
                if (hasQueuedPredecessors())
                    return -1;
                //獲取state的值
                int available = getState();
                //可用訊號-獲取數量=剩餘可用數量
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

複製程式碼

相關文章