AbstractQueuedSynchronizer源碼分析

1、簡介

        AQS是JUC框架中重要的類,經過它來實現獨佔鎖和共享鎖的,內部不少類都是經過AQS來實現的,好比CountDownLatch、ReentrantLock、ReentrantReadWriteLock、Semaphore。本章是對AbstractQueuedSynchronizer源碼進行分析。從獨佔鎖的獲取、釋放,共享鎖的獲取、釋放,以及Condition的await、signal三方面對源碼進行分析。先知道AQS的這幾點注意事項一、Condition條件變量只支持在獨佔鎖狀態下二、AQS支持同步隊列和條件隊列(條件隊列的數目根據Condition實例的數目),只有同步隊列中的節點線程才能獲取鎖三、AQS是個抽象類,提供獨佔鎖和共享鎖的公有方法,子類須要實現的幾個模板方法,①tryAcquire②tryRelease③tryAcquireShared④tryReleaseShared⑤isHeldExclusively。這幾點在下面代碼解析會分析到。還有一個AbstractQueuedLongSynchronizer類,它與AQS功能和實現幾乎同樣,惟一不一樣的是AQLS中表明鎖被獲取次數的屬性state類型是long類型,而AQS中該成員變量是int類型。AQS源碼對應的jdk版本是1.8。java

2、類關係


//此類只提供保存和獲取獨佔鎖線程,子類可使用適當的保留值來幫助控制和監控訪問並提供診斷
public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
    
    private static final long serialVersionUID = 3737899427754241961L;
    
    protected AbstractOwnableSynchronizer() { }
    
    //獨佔鎖擁有者線程
    private transient Thread exclusiveOwnerThread;
     
    //設置獨佔鎖的擁有者線程,訪問權限protected,同包或者子類使用
    protected final void setExclusiveOwnerThread(Thread thread) {
        //將傳入進來的線程賦值給獨佔鎖擁有者線程
        exclusiveOwnerThread = thread;
    }
    
    //獲取獨自鎖的擁有者線程,訪問權限protected,只能在同包或者子類使用
    protected final Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }
}複製代碼

3、屬性

//同步隊列的頭節點
private transient volatile Node head;
//同步隊列的尾節點
private transient volatile Node tail;
//同步狀態
private volatile int state;
//若是超時時間小於此閾值,不阻塞線程,讓其自旋,在doAcquireNanos、doAcquireSharedNanos、awaitNanos、await(long time, TimeUnit unit)方法使用到
static final long spinForTimeoutThreshold = 1000L;
//獲取UnSafe使用,若是對UnSafe使用不清楚的,能夠看下我分享的UnSafe的使用
private static final Unsafe unsafe = Unsafe.getUnsafe();
//屬性state的相對偏移量,相對AbstractQueuedSynchronizer實例的起始內存位置的相對偏移量,定義成靜態的緣由是,屬性的相對實例的偏移量都是相等的
private static final long stateOffset;
//屬性head的相對偏移量
private static final long headOffset;
//屬性tail的相對偏移量
private static final long tailOffset;
//內部類Node實例的屬性waitStatus的相對偏移量
private static final long waitStatusOffset;
//內部類Node實例的屬性next的相對偏移量
private static final long nextOffset;
static {
    try {
        //使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性state的相對偏移量
        stateOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        //使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性head的相對偏移量
        headOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        //使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性tail的相對偏移量
        tailOffset = unsafe.objectFieldOffset
                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        //使用UnSafe實例獲取AbstractQueuedSynchronizer內部類Node的屬性waitStatus的相對偏移量
        waitStatusOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("waitStatus"));
        //使用UnSafe實例獲取AbstractQueuedSynchronizer內部類Node的屬性next的相對偏移量
        nextOffset = unsafe.objectFieldOffset
                (Node.class.getDeclaredField("next"));
    } catch (Exception ex) { throw new Error(ex); }    
}複製代碼

4、內部類

  1. Node類

    //經過Node咱們能夠實現兩個隊列,一是經過prev和next屬性實現CLH隊列(線程同步隊列,雙向隊列),二是nextWaiter屬性實現Condition條件上的等待條件隊列(單向隊列),在Condition中會詳細介紹。
    static final class Node {
            //當前節點是獲取共享鎖的標記
            static final Node SHARED = new Node();
            //當前節點是獲取獨佔鎖的標記
            static final Node EXCLUSIVE = null;
            
            //屬性waitStatus的值,標誌節點對應的線程被取消
            static final int CANCELLED =  1;
            //屬性waitStatus的值,標誌當前節點的next節點的線程(即隊列中當前節點的下一個節點)須要被阻塞
            static final int SIGNAL    = -1;
            //屬性waitStatus的值,標誌當前節點在Condition條件下等待阻塞,在Condition實例的await系列方法中使用,新建一個waitStatus的值爲CONDITION的節點Node,將其加入到Condition中的條件隊列中,在Condition實現類詳細介紹
            static final int CONDITION = -2;
            //屬性waitStatus的值,標誌着下一個acquireShared方法線程應該被容許,在獲取共享鎖
            static final int PROPAGATE = -3;
            
            //標記着當前節點的狀態,默認狀態是0,小於0的狀態值都是有特殊做用,大於0的狀態值表示已取消
            volatile int waitStatus;
            
            //使用prev和next實現同步隊列,即雙向鏈表,當前節點的前驅節點 
            volatile Node prev;
            
            //當前節點的下一節點 
            volatile Node next;
            
            //當前節點對應的線程
            volatile Thread thread;
            
            //有兩種做用:一、表示下一個在Condition條件上等待的節點,調用Condition中await和signal方法,當前節點的線程是擁有獨佔鎖的線程二、表示同步隊列中的節點是共享模式仍是獨佔模式
            Node nextWaiter;
            
            //判斷當前節點是否是共享模式
            final boolean isShared() {
                return nextWaiter == SHARED;
            }
            
            //獲取當前節點的前驅節點,若是爲null,則拋出空指針異常
            final Node predecessor() throws NullPointerException {
                //當前節點的前驅節點
                Node p = prev;
                //若是前驅節點爲空
                if (p == null)
                    //拋出空指針異常
                    throw new NullPointerException();
                else
                    //返回當前節點的前驅節點
                    return p;
            }
            
            //在建立鏈表頭head,或者建立節點共享鎖標記屬性SHARED值
            Node() {    
            }
            
            //在addWaiter方法中使用
            Node(Thread thread, Node mode) {
                //當前節點的模式,是屬於共享模式,仍是獨佔模式 
                this.nextWaiter = mode;
                //將傳入進來的線程賦值給節點屬性thread
                this.thread = thread;
            }
            
            //在Condition條件中使用
            Node(Thread thread, int waitStatus) {
                //將傳入節點的狀態值賦值給節點屬性waitStatus 
                this.waitStatus = waitStatus;
                //將傳入進來的線程賦值給節點屬性thread
                this.thread = thread;
            }
    }
    
    複製代碼

  2. ConditionObject類

    public interface Condition {
        //如下方法都會詳細在ConditionObject實現類中介紹 
        void await() throws InterruptedException;
        
        void awaitUninterruptibly();
        
        long awaitNanos(long nanosTimeout) throws InterruptedException;
        
        boolean await(long time, TimeUnit unit) throws InterruptedException;
    
        boolean awaitUntil(Date deadline) throws InterruptedException;
        
        void signal();
    
        void signalAll();
    }
    
    
    
    public class ConditionObject implements Condition, java.io.Serializable {
            private static final long serialVersionUID = 1173984872572414699L;
            //當前Condition實例的條件隊列的第一個節點
            private transient Node firstWaiter;
            //當前Condition實例的條件隊列的最後一個節點 
            private transient Node lastWaiter;
            //構造函數
            public ConditionObject() { }
            
            //若是尾節點的狀態值不是CONDITION值,清除條件隊列中取消的節點,修改條件隊列的第一個節點和最後一個節點,建立新節點,將其新節點作爲條件隊列的尾節點
            private Node addConditionWaiter() {
                //獲取條件隊列的最後一個節點
                Node t = lastWaiter;
                // If lastWaiter is cancelled, clean out.
                //若是條件隊列中的最後一個節點不爲空,而且狀態值不是CONDITION,即最後等待節點已取消
                if (t != null && t.waitStatus != Node.CONDITION) {
                    //移除條件隊列中的已取消的節點,從新設置firstWaiter、lastWaiter節點,詳細的能夠看下面對unlinkCancelledWaiters方法的介紹
                    unlinkCancelledWaiters();
                    //從新獲取條件隊列的最後一個節點
                    t = lastWaiter;
                }
                //建立新節點,傳入當前線程和節點的狀態值Node.CONDITION
                Node node = new Node(Thread.currentThread(), Node.CONDITION);
                //若是尾節點爲空
                if (t == null)
                    //將其新節點作爲條件隊列的第一個節點
                    firstWaiter = node;
                else
                    //將條件隊列中的上一個尾節點
                    t.nextWaiter = node;
                //將其新建的節點作爲條件隊列的最後一個節點
                lastWaiter = node;
                //返回新建的節點
                return node;
            }
            
            //只將一個條件隊列中不爲空、狀態值爲CONDITION的第一個節點加入到同步隊列中,傳入條件隊列的頭結點,將其移動同步隊列中,若是傳入的節點已取消,會將其傳入節點的下一個不爲空、狀態值爲CONDITION的節點移到同步隊列中
            private void doSignal(Node first) {
                do {
                    //傳入的節點的下一個等待節點爲空
                    if ( (firstWaiter = first.nextWaiter) == null)
                        //將其條件隊列的尾節點設置爲空 
                        lastWaiter = null;
                    //加快gc回收,將其傳入節點的下一節點置爲空 
                    first.nextWaiter = null;
                    //能夠看下面對transferForSignal方法的詳細介紹,將其傳入節點(狀態值爲CONDITION)移到同步隊列中,若是當前加入同步隊列節點的前置節點狀態爲已取消,或者將其前置節點的狀態值設置爲SIGNAL失敗,喚醒加入的節點對應的線程
                } while (!transferForSignal(first) && //找到條件隊列中節點不爲空的而且狀態值爲CONDITION的節點加入到同步隊列中
                         (first = firstWaiter) != null);
            }
            
            //將其條件隊列中的全部不爲空、狀態值爲CONDITION的節點加入到同步隊列中,從傳入條件隊列的頭節點開始
            private void doSignalAll(Node first) {
                //將其條件隊列的頭尾節點都置爲空
                lastWaiter = firstWaiter = null;
                //從頭結點開始循環獲取條件隊列中的全部節點
                do {
                    //獲取頭結點的下一節點
                    Node next = first.nextWaiter;
                    //加快gc,將其頭節點的關聯的下一節點置爲空
                    first.nextWaiter = null;
                    //能夠看下面對transferForSignal方法的詳細介紹,將其傳入節點(狀態值爲CONDITION)移到同步隊列中,若是當前加入同步隊列節點的前置節點狀態爲已取消,或者將其前置節點的狀態值設置爲SIGNAL失敗,喚醒加入的節點對應的線程
                    transferForSignal(first);
                    //將下一節點設置爲頭結點
                    first = next;
                } while (first != null);//直到節點爲空,即條件隊列結束
            }
            
            //將已取消的節點從條件隊列中移除 
            private void unlinkCancelledWaiters() {
                //獲取條件隊列的頭節點
                Node t = firstWaiter;
                //臨時變量,存放最新的不爲空、狀態值爲Node.CONDITION的節點,目的是爲了設置下一節點不爲空、狀態值爲Node.CONDITION的節點
                Node trail = null;
                //頭結點不爲空
                while (t != null) {
                    //獲取頭節點的下一節點
                    Node next = t.nextWaiter;
                    //若是頭節點狀態值不是Node.CONDITION,此節點已取消 
                    if (t.waitStatus != Node.CONDITION) {
                        //加快gc,此已取消節點
                        t.nextWaiter = null; 
                        //若是最新的不爲空、狀態值爲CONDITION的節點爲空
                        if (trail == null)
                            //將下一節點設置爲頭結點
                            firstWaiter = next;
                        else
                            //將最新的不爲空、狀態值爲CONTIDION的節點和下一節點連起來
                            trail.nextWaiter = next;
                        //若是下一節點爲空,代表條件隊列已經沒有節點
                        if (next == null)
                            //將最新的不爲空、狀態值爲CONTIDION的節點賦值給尾節點 
                            lastWaiter = trail;
                    }
                    else
                        //將t賦值給trail
                        trail = t;
                    將下一節點作爲頭節點
                    t = next;
                }
            }
            
            // public methods
            //將條件隊列中的不爲空、狀態值爲CONDITION頭節點移動到同步隊列中 
            public final void signal() {
                //調用signal方法的線程,不是擁有排他鎖的線程就會拋出IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
                if (!isHeldExclusively()) //isHeldExclusively方法子類得重寫,不然直接拋出UnsupportedOperationException
                    throw new IllegalMonitorStateException();
                //獲取條件隊列的頭結點
                Node first = firstWaiter;
                //若是條件隊列不爲空
                if (first != null)
                    //調用上面介紹的doSignal方法,詳細的能夠看上面的介紹,只將一個條件隊列中不爲空、狀態值爲CONDITION的第一個節點加入到同步隊列中,傳入條件隊列的頭結點,將其移動同步隊列中,若是傳入的節點已取消,會將其傳入節點的下一個不爲空、狀態值爲CONDITION的節點移到同步隊列中
                    doSignal(first);
            }
            
            //將條件隊列中的全部不爲空,狀態值爲CONDITION的節點移動到同步隊列中
            public final void signalAll() {
                /調用signalAll方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                //獲取條件隊列中的頭節點
                Node first = firstWaiter;
                //若是頭節點不爲空,即條件隊列中存在節點
                if (first != null)
                    //調用上面介紹的doSignalAll方法,doSignalAll方法的詳細介紹能夠看上面對此方法的介紹,將其條件隊列中的全部不爲空、狀態值爲CONDITION的節點加入到同步隊列中,從傳入條件隊列的頭節點開始
                    doSignalAll(first);
            }
            
            //新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待。若是線程等待期間發出中斷請求,不會產生中斷異常
            public final void awaitUninterruptibly() {
                //爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
                Node node = addConditionWaiter();
                //釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
                int savedState = fullyRelease(node);
                //初始化中斷標誌位爲false
                boolean interrupted = false;
                //循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
                while (!isOnSyncQueue(node)) {
                    //阻塞當前線程
                    LockSupport.park(this);
                    //若是當前線程被中斷 
                    if (Thread.interrupted())
                        //將中斷標誌位設置爲true
                        interrupted = true;
                }
                //節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
                if (acquireQueued(node, savedState) || interrupted)
                    //acquireQueued方法返回true,即當前線程被中斷過,或者interruped標誌位爲true調用當前線程的interrupt方法
                    selfInterrupt();//Thread.currentThread().interrupt();
            }
    
            //從新中斷的標誌位
            private static final int REINTERRUPT =  1;
            //拋出中斷異常的標誌位 
            private static final int THROW_IE    = -1;
            
            //檢查傳入節點在等待時,傳入節點對應的線程是否有發生被中斷請求
            //若是其餘線程沒有調用傳入節點線程的interrupt方法,即中斷請求,返回0
            //若是此節點對應的線程有被中斷請求,而且中斷請求在signalled(即調用signal或signalAll)以前返回THROW_IE ,由於在調用await方法時,會新建一個節點(狀態值爲CONDITION)加入到條件隊列中,好比調用await方法傳入超時時間,阻塞線程在超時自動被喚醒,此時節點尚未被signal,可是有其餘線程調用此節點對應的線程interrupt方法
            //若是中斷請求是在singal、signalAll方法以後,返回從新中斷的標誌位
            private int checkInterruptWhileWaiting(Node node) {
                return Thread.interrupted() ?
                    //transferAfterCanceledWait方法,看下面的詳細介紹 
                    (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                    0;
            }
    
            //若是傳入進來的參數interruptMode是THROW_IE,就拋出InterruptedException異常,若是interruptMode是REINTERRUPT,則當前線程再次調用interrupt方法,再次發出中斷請求,不然就什麼都不作
            private void reportInterruptAfterWait(int interruptMode) throws InterruptedException {
                //若是interruptMode是THROW_IE 
                if (interruptMode == THROW_IE)
                    //拋出InterruptedException異常
                    throw new InterruptedException();
                //若是interruptMode是REINTERRUPT,從新調用當前線程的interrupt方法,再次發出中斷請求
                else if (interruptMode == REINTERRUPT)
                    selfInterrupt();
            }
    
            //新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待。若是線程等待期間發出中斷請求,則拋出中斷異常
            public final void await() throws InterruptedException {
                //若是當前線程已被中斷
                if (Thread.interrupted())
                    //拋出中斷異常
                    throw new InterruptedException();
                //爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
                Node node = addConditionWaiter();
                //釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
                int savedState = fullyRelease(node);
                //線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位 
                int interruptMode = 0;
                //循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
                while (!isOnSyncQueue(node)) {
                    //阻塞當前線程
                    LockSupport.park(this);
                    //若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                        break;
                }
                //節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    interruptMode = REINTERRUPT;
                //若是當前節點的下一個節點不爲空 
                if (node.nextWaiter != null) // clean up if cancelled
                    //將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
                    unlinkCancelledWaiters();
                //是否要拋出中斷異常,或者發出中斷請求
                if (interruptMode != 0)
                    //能夠看上面對reportInterruptAfterWait方法的介紹
                    reportInterruptAfterWait(interruptMode);
            }
            
            //@param nanpsTimeout超時時間,單位爲納秒
            //@return 死亡時間減去當前時間的時間戳
            //新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者超時將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
            public final long awaitNanos(long nanosTimeout) throws InterruptedException {
                //若是線程已被中斷 
                if (Thread.interrupted())
                    //拋出中斷異常
                    throw new InterruptedException();
                //爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
                Node node = addConditionWaiter();
                //釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
                int savedState = fullyRelease(node);
                //獲取死亡時間,即當前時間加上傳入的超時時間 
                final long deadline = System.nanoTime() + nanosTimeout;
                //線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位 
                int interruptMode = 0;
                //循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
                while (!isOnSyncQueue(node)) {
                    //若是傳入的超時時間小於等於0
                    if (nanosTimeout <= 0L) {
                        //transferAfterCanceledWait方法,看下面的詳細介紹 
                        transferAfterCancelledWait(node);
                        //退出循環
                        break;
                    }
                    //若是超時時間大於等於spinForTimeoutThreshold閾值,纔會阻塞當前線程,不然讓其線程自旋一段時間
                    if (nanosTimeout >= spinForTimeoutThreshold)
                        //超時的阻塞當前線程,this是阻塞當前線程的監控對象
                        LockSupport.parkNanos(this, nanosTimeout);
                    //若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                        //退出循環 
                        break;
                    //死亡時間減去當前時間,獲得超時時間
                    nanosTimeout = deadline - System.nanoTime();
                }
                //節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    //將其標誌節點interruptMode設置爲從新中斷標誌位
                    interruptMode = REINTERRUPT;
                //若是當前節點的下一個節點不爲空 
                if (node.nextWaiter != null)
                    //將已取消的節點從條件隊列中移除,能夠看上面對unlinkCancelledWaiters方法介紹
                    unlinkCancelledWaiters();
                //是否要拋出中斷異常,或者發出中斷請求
                if (interruptMode != 0)
                    //能夠看上面對reportInterruptAfterWait方法的介紹
                    reportInterruptAfterWait(interruptMode);
                //返回死亡時間減去當前時間的時間戳
                return deadline - System.nanoTime();
            }
            
            //@param deadline 死亡時間
            //@return 節點對應的線程被中斷是否比佔有獨佔鎖的線程調用signal、signalAll方法將當前節點從條件隊列移到同步隊列中以前,若是是返回值爲false,不然返回true,表示正常超時,而不是由中斷退出
            //新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者到死亡時間將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
            public final boolean awaitUntil(Date deadline) throws InterruptedException {
                //死亡時間的時間戳 
                long abstime = deadline.getTime();
                //若是線程已被中斷 
                if (Thread.interrupted())
                    //拋出中斷異常
                    throw new InterruptedException();
                //爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
                Node node = addConditionWaiter();
                //釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
                int savedState = fullyRelease(node);
                //是否超時的標記位
                boolean timedout = false;
                //線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
                int interruptMode = 0;
                //循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
                while (!isOnSyncQueue(node)) {
                    //若是當前時間大於死亡時間 
                    if (System.currentTimeMillis() > abstime) {
                        //transferAfterCanceledWait方法,看下面的詳細介紹 
                        timedout = transferAfterCancelledWait(node);
                        //退出循環
                        break;
                    }
                    //阻塞當前線程直到死亡時間、或者擁有獨佔鎖的線程調用signal、signalAll方法喚醒線程
                    LockSupport.parkUntil(this, abstime);
                    //若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                       //退出循環 
                       break;
                }
                //節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹 if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                   //將其標誌節點interruptMode設置爲從新中斷標誌位
                   interruptMode = REINTERRUPT;
                //若是當前節點的下一個節點不爲空 
                if (node.nextWaiter != null)
                    //將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
                    unlinkCancelledWaiters();
                //是否要拋出中斷異常,或者發出中斷請求
                if (interruptMode != 0)
                    //能夠看上面對reportInterruptAfterWait方法的介紹
                    reportInterruptAfterWait(interruptMode);
                //返回表示此方法是正常超時結束,仍是由中斷退出結束 
                return !timedout;
            }
            
            //相比awaitNanos方法超時時間更加可控,能夠傳入不一樣的超時單位
            //@return 節點對應的線程被中斷是否比佔有獨佔鎖的線程調用signal、signalAll方法將當前節點從條件隊列移到同步隊列中以前,若是是返回值爲false,不然返回true,表示正常超時,而不是由中斷退出
            //新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者超時將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
            public final boolean await(long time, TimeUnit unit) throws InterruptedException {
                //將超時時間轉化爲納秒
                long nanosTimeout = unit.toNanos(time);
                //若是線程已被中斷 
                if (Thread.interrupted())
                    //拋出中斷異常
                    throw new InterruptedException();
                //爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
                Node node = addConditionWaiter();
                //釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
                int savedState = fullyRelease(node);
                //獲取死亡時間,即當前時間加上傳入的超時時間 
                final long deadline = System.nanoTime() + nanosTimeout;
                //當前await方法是否正常超時結束,仍是由中斷退出結束
                boolean timedout = false;
                //線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
                int interruptMode = 0;
                //循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
                while (!isOnSyncQueue(node)) {
                    //若是傳入的超時時間小於等於0
                    if (nanosTimeout <= 0L) { 
                        //transferAfterCanceledWait方法,看下面的詳細介紹 
                        timedout = transferAfterCancelledWait(node);
                        //退出循環
                        break;
                    }
                    //若是超時時間大於等於spinForTimeoutThreshold閾值,纔會阻塞當前線程,不然讓其線程自旋一段時間
                    if (nanosTimeout >= spinForTimeoutThreshold)
                        //超時的阻塞當前線程,this是阻塞當前線程的監控對象
                        LockSupport.parkNanos(this, nanosTimeout);
                    //若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
                    if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                        //退出循環
                        break;
                    //返回死亡時間減去當前時間的時間戳
                    nanosTimeout = deadline - System.nanoTime();
                }
                //節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
                if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                    //將其標誌節點interruptMode設置爲從新中斷標誌位
                    interruptMode = REINTERRUPT;
                //若是當前節點的下一個節點不爲空 
                if (node.nextWaiter != null)
                    //將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
                    unlinkCancelledWaiters();
                //是否要拋出中斷異常,或者發出中斷請求
                if (interruptMode != 0)
                    //能夠看上面對reportInterruptAfterWait方法的介紹
                    reportInterruptAfterWait(interruptMode);
                //返回表示此方法是正常超時結束,仍是由中斷退出結束 
                return !timedout;
            }
    
            //判斷Condition實例的外部類AQS和傳入進來的AQS是否相等,判斷Condition實例是否歸屬於傳入進來的AQS 
            final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
                // AbstractQueuedSynchronizer.this在內部類實例中常用,獲取外部類的實例
                return sync == AbstractQueuedSynchronizer.this;
            }
            
            //判斷條件隊列中是否有等待的節點
            protected final boolean hasWaiters() {
                /調用hasWaiters方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                //從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    //判斷條件隊列中的是否有節點的狀態值爲CONDITION
                    if (w.waitStatus == Node.CONDITION)
                        //若是是直接返回true
                        return true;
                }
                //不然直接返回false
                return false;
            }
            
            //獲取條件隊列中有多少個等待節點(狀態值爲CONDITION) 
            protected final int getWaitQueueLength() {
               //調用getWaitQueueLength方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
               if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                //等待節點數目
                int n = 0;
                //從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    //若是條件隊列中等待節點的狀態值爲CONDITION
                    if (w.waitStatus == Node.CONDITION)
                        //等待節點加1
                        ++n;
                }
                //返回等待節點
                return n;
            }
            
            //獲取條件隊列中全部等待節點(狀態值爲CONDITION)的線程,返回線程集合 
            protected final Collection<Thread> getWaitingThreads() {
                //調用getWaitingThreads方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                //全部等待節點對應的線程集合
                ArrayList<Thread> list = new ArrayList<Thread>();
                //從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
                for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
                    //若是條件隊列的等待節點的狀態值爲CONDITION
                    if (w.waitStatus == Node.CONDITION) {
                        //獲取等待節點對應的線程
                        Thread t = w.thread;
                        //若是節點對應的線程不爲空
                        if (t != null)
                            //將其線程加入到集合中 
                            list.add(t);
                    }
                }
                //返回全部等待節點對應的線程集合
                return list;
            }
    }複製代碼

5、同步隊列

  1. 同步隊列頭head設置

    //經過UnSafe的cas函數設置AQS的屬性head值,僅僅在enq方法中,返回設置釋放成功,使用cas保證多線程安全
    private final boolean compareAndSetHead(Node update) {
        //cas經過AQS實例和其屬性head偏移量,若是頭結點爲空,將其空設置爲update值
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }
    
    // 從新設置同步隊列頭結點head,只在acquire系列的方法中調用
    private void setHead(Node node) {
        head = node;
        //當前節點對應的當前線程已經獲取到鎖了,將當前節點對應的線程置爲空
        node.thread = null;
        //當前節點前一個節點已經沒有意義,將當前節點對應的前置節點置爲空
        node.prev = null;
    }
    複製代碼
  2. 同步隊列尾tail設置

    //經過CAS函數設置tail值,僅僅在enq方法中調用,經過CAS函數設置tail值,保證多線程安全
    private final boolean compareAndSetTail(Node expect, Node update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
    
    // 向同步隊列尾插入新節點,若是隊列沒有初始化,先初始化同步隊列的頭尾節點。返回原先的同步隊列尾節點
     private Node enq(final Node node) {
            for (;;) {
                //獲取同步隊列的尾節點
                Node t = tail;
                //t尾節點爲空,表示隊列爲空,先初始化隊列
                if (t == null) {
                    // 採用CAS函數即原子操做方式,設置隊列頭head值。
                    // 若是成功,再將head值賦值給鏈表尾tail。若是失敗,表示head值已經被其餘線程,那麼就進入循環下一次
                    if (compareAndSetHead(new Node()))
                        tail = head;
                } else {
                    // 新添加的node節點的前一個節點prev指向原來的隊列尾tail
                    node.prev = t;
                    // 採用CAS函數即原子操做方式,設置新隊列尾tail值。
                    if (compareAndSetTail(t, node)) {
                        // 設置老的隊列尾tail的下一個節點next指向新添加的節點node
                        t.next = node;
                        return t;
                    }
                }
            }
    }
    複製代碼

6、獨佔鎖

  1. 獨佔鎖的獲取

    //獲取獨佔鎖。若是沒有立刻獲取到,線程就會阻塞等待,直到獲取到獨佔鎖。不會響應中斷異常
    public final void acquire(int arg) {
        //1. 當前線程先調用tryAcquire方法,嘗試獲取獨佔鎖,若是返回true,表示獲取到鎖,不須要執行acquireQueued方法。
        //2. 若是tryAcquire方法獲取獨佔鎖失敗,調用acquireQueued方法,先調用addWaiter方法爲當前線程建立一個狀態爲獨佔模式的節點Node,並使用cas將其作爲同步隊列尾節點加入隊列中,
        //若是當前加入節點的前置節點爲頭節點,當前線程調用tryAcquire方法去嘗試獲取鎖,若是不成功,就會根據前置節點的狀態來判斷是否讓當前線程阻塞,當前線程阻塞被喚醒。
        //acquireQueued方法返回值表示在線程等待過程當中,是否有另外一個線程調用該線程的interrupt方法,發起中斷請求。
        //tryAcquire是個模板方法,能夠看下面對此方法的介紹,acquireQueued方法能夠看下面對此方法的介紹
        if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            //當前線程執行acquireQueued方法的過程當中有其餘線程調用該線程的interrupt方法,發起中斷請求,從新調用當前線程的interrupt方法,中斷請求
            selfInterrupt();
    }
    
     // 嘗試去獲取獨佔鎖,當即返回。若是返回true表示獲取獨佔鎖成功,此方法爲模板方法,須要子類進行重寫,能夠看下面ReentrantReadWriteLock類中對AQS的tryAcquire方法實現
    protected boolean tryAcquire(int arg) {
         //拋出UnsupportedOperationException異常
         throw new UnsupportedOperationException();
    }
    
    //ReentrantReadWriteLock類中對AQS的tryAcquire方法實現,詳細的介紹,會在分析ReentrantReadWriteLock源碼時進行詳細介紹
    //嘗試獲取同步隊列的獨佔鎖,與非公平鎖最大的不一樣就是調用hasQueuedPredecessors()方法,hasQueuedPredecessors方法返回true,表示等待線程隊列中有一個線程在當前線程以前,根據公平鎖的規則,當前線程不能獲取鎖。
    protected final boolean tryAcquire(int acquires) {
                //獲取當前線程 
                Thread current = Thread.currentThread();
                //獲取當前鎖的狀態,即AQS中的屬性值
                int c = getState();
                //由狀態獲取獨佔鎖的個數,鎖的狀態也是根據獨佔鎖的個數或者共享鎖的個數來進行判斷
                int w = exclusiveCount(c);
                //若是c==0表示當前鎖是空閒的,若是鎖狀態不等於0,代表鎖狀態有多是讀鎖或者寫鎖
                if (c != 0) {
                    //若是獨佔鎖的個數等於0,代表當前鎖屬於共享鎖模式,直接返回失敗,若是獨佔鎖的個數不等於0,而且當前擁有獨佔鎖的線程不是當前,也是直接返回失敗
                    if (w == 0 || current != getExclusiveOwnerThread())
                        return false;
                    //若是獨佔鎖的個數加上傳入進來的請求獨佔鎖個數大於MAX_COUNT,直接拋出錯誤,超過最大的獨佔鎖個數
                    if (w + exclusiveCount(acquires) > MAX_COUNT)
                        throw new Error("Maximum lock count exceeded");
                    //不然的話更新鎖的狀態 
                    setState(c + acquires);
                    //返回獲取獨佔鎖成功
                    return true;
                }
                //非公平鎖writerShouldBlock直接返回false,公平鎖writeShouldBlock會調用hasQueuedPredecessors方法
                if (writerShouldBlock() ||
                    !compareAndSetState(c, c + acquires))
                    //返回獲取獨佔鎖失敗
                    return false;
                //將當前線程設置爲擁有獨佔鎖的線程
                setExclusiveOwnerThread(current);
                //返回獲取獨佔鎖成功
                return true;
    }
    
    /** * 獲取獨佔鎖的acquire系列方法,都會使用這個方法來獲取獨佔鎖 * 循環經過tryAcquire方法不斷去獲取鎖,若是沒有獲取成功,若是此節點的前置節點的狀態值爲SIGNAL * 需調用parkAndCheckInterrupt方法,讓當前線程阻塞 * @param node 想要獲取獨佔鎖鎖的節點 * @param arg 獲取獨佔鎖的個數 * @return 返回true,表示在線程等待的過程當中,線程被中斷了 */
    final boolean acquireQueued(final Node node, int arg) {
            //設置失敗的標誌位
            boolean failed = true;
            try {
                //表示節點對應的線程在等待過程當中,是否被中斷的標誌位
                boolean interrupted = false;
                //經過死循環,直到node節點對應的線程獲取到鎖,才返回
                for (;;) {
                    //獲取當前節點的前置節點
                    final Node p = node.predecessor();
                    //若是當前節點的前一個節點爲同步隊列的頭節點head,當前線程嘗試使用tryAcquire方法獲取鎖,若是獲取鎖成功,那麼當前線程就不須要阻塞等待,繼續執行
                    if (p == head && tryAcquire(arg)) {
                        //將節點node設置爲同步隊列的頭節點
                        setHead(node);
                        //將節點node的前置節點設置爲空,加快gc
                        p.next = null; // help GC
                        //失敗的標誌位設置爲false
                        failed = false;
                        //返回是否中斷的標誌位 
                        return interrupted;
                    }
                    //判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法會在下面詳細進行介紹
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        //若是方法parkAndCheckInterrupt的返回值爲true,代表節點對應的線程在等待時,有其餘線程調用此線程的interrupt方法,中斷請求
                        interrupted = true;
                }
            } finally {
                //在獲取獨佔鎖的過程當中失敗,將當前節點從同步隊列中移除
                if (failed)
                    //cancelAcquire方法會在下面詳細進行介紹
                    cancelAcquire(node);
            }
    }
    
    /** * 根據前一個節點pred的狀態,來判斷當前節點對應的線程是否應該被阻塞 * @param pred : node節點的前一個節點 * @param node : 要獲取獨佔鎖的節點 * @return 返回true 表示當前線程應該被阻塞,而後調用parkAndCheckInterrupt方法來阻塞當前線程 */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
            //獲取前置節點的狀態值
            int ws = pred.waitStatus;
            //若是前置節點的狀態值爲SIGNAL 
            if (ws == Node.SIGNAL)
                // 若是前一個pred的狀態是Node.SIGNAL,那麼直接返回true,當前線程應該被阻塞
                return true;
            //若是前置節點已經取消,循環獲取不是取消的前置節點 
            if (ws > 0) {
                // 若是前一個節點狀態是Node.CANCELLED(大於0就是CANCELLED),
                // 表示前一個節點所在線程已經被喚醒了,要從CLH隊列中移除CANCELLED的節點。
                // 因此從pred節點一直向前查找直到找到不是CANCELLED狀態的節點,並把它賦值給node.prev,
                // 表示node節點的前一個節點已經改變。
                do {
                    //從新賦值當前節點的前置節點
                    node.prev = pred = pred.prev;
                } while (pred.waitStatus > 0);
                //不是取消的前置節點的下一節點從新賦值爲當前節點 
                pred.next = node;
            } else {
                // 此時前一個節點pred的狀態只能是0或者PROPAGATE,不多是CONDITION狀態
                // CONDITION(只在condition條件隊列中節點存在,CLH同步隊列中沒有此狀態的節點)
                // 將前一個節點pred的狀態設置成Node.SIGNAL,這樣在下一次循環時,就是直接阻塞當前線程
                compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
            }
            //返回要獲取獨佔鎖的節點對應的線程不會阻塞 
            return false;
    }
    
    private final boolean parkAndCheckInterrupt() {
            //阻塞當前線程
            LockSupport.park(this);
            //當前線程被喚醒後,返回當前線程的中斷標誌位
            return Thread.interrupted();
    }
    
    //將傳入進來的節點從同步隊列中移除,將傳入節點對應的線程置爲空,狀態置爲CANCELLED
    private void cancelAcquire(Node node) {
            //若是當前節點爲空,直接跳過
            if (node == null)
                return;
            //將當前節點對應的線程置爲空
            node.thread = null;
    
            //獲取當前要取消節點的前置節點
            Node pred = node.prev;
            //循環跳過前置節點狀態爲CANNELLED的值
            while (pred.waitStatus > 0)
                node.prev = pred = pred.prev;
    
            //獲取狀態不是取消的前置的節點的下一個節點,在設置前置節點的下一個節點使用到
            Node predNext = pred.next;
    
            //將當前要取消的節點狀態賦值爲CANCELLED
            node.waitStatus = Node.CANCELLED;
    
            //若是要取消節點爲尾節點,將尾節點設置爲要取消節點的前一個節點
            if (node == tail && compareAndSetTail(node, pred)) {
                //若是設置成功,將要取消節點的前置節點的下一個節點設置爲空
                compareAndSetNext(pred, predNext, null);
            } else {
                int ws;
                //若是前置不是頭節點,而且前置節點的狀態值爲SIGNAL,或者 
                if (pred != head &&
                    ((ws = pred.waitStatus) == Node.SIGNAL ||
                     (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                    pred.thread != null) {
                    //獲取要取消節點的下一個節點
                    Node next = node.next;
                    //要取消節點的下一個節點不爲空,而且狀態值小於等於0,即不是取消狀態值CANCELLED 
                    if (next != null && next.waitStatus <= 0)
                        //將要取消節點的前置節點和要取消節點的下一節點鏈接起來
                        compareAndSetNext(pred, predNext, next);
                } else {
                    //不然的話喚醒node節點的下一個節點,在下面會對unparkSuccessor方法進行詳細介紹
                    unparkSuccessor(node);
                }
                //將要取消節點的下一節點設置爲自身,加快gc
                node.next = node; // help GC
            }
    }
    
    //喚醒傳入節點的下一個不爲空、狀態值不是已取消CANCELLED節點對應的線程
    private void unparkSuccessor(Node node) {
            //獲取傳入節點的狀態
            int ws = node.waitStatus;
            //若是狀態小於0,將其狀態設置爲0 
            if (ws < 0)
                compareAndSetWaitStatus(node, ws, 0);
    
            //獲取傳入節點的下一節點
            Node s = node.next;
            //若是下一節點爲空或者是已取消節點 
            if (s == null || s.waitStatus > 0) {
                //將下一節點置爲空 
                s = null;
                //從同步隊列的尾節點開始,獲取不等於空,而且節點不等於傳入節點的前置節點,即從新尋找傳入節點的下一個不爲空,而且沒有取消的節點進行喚醒 
                for (Node t = tail; t != null && t != node; t = t.prev)
                    //t節點不是已取消節點
                    if (t.waitStatus <= 0)
                        //將下一節點s賦值爲t
                        s = t;
            }
            //若是下一節點s不爲空
            if (s != null)
                //喚醒此節點s對應的線程
                LockSupport.unpark(s.thread);
    }
    複製代碼

  2. 獨佔鎖的釋放

    //調用release方法的線程,是擁有獨佔鎖的線程,釋放獨佔鎖的操做
    public final boolean release(int arg) {
            //線程首先調用tryRelease方法,嘗試去釋放鎖,此方法爲模板方法,由子類具體實現
            if (tryRelease(arg)) {
                //若是tryRelease釋放鎖成功,獲取同步隊列的頭結點
                Node h = head;
                //若是頭結點不爲空,而且狀態值不等於0,無論頭結點是已取消,仍是其餘狀態 
                if (h != null && h.waitStatus != 0)
                    //喚醒頭結點的下一個不爲空,而且狀態值不爲CANCELLED的下一個節點,能夠看上面對unparkSuccessor方法的介紹
                    unparkSuccessor(h);
                //釋放獨佔鎖成 
                return true;
            }
            //釋放獨佔鎖失敗
            return false;
    }
    
    //AQS的模板方法,由具體的子類實現
    protected boolean tryRelease(int arg) {
        //拋出UnsupportedOperationException異常
        throw new UnsupportedOperationException();
    }
    
    //ReentrantReadWriteLock中Sync的tryRelease方法實現
    protected final boolean tryRelease(int releases) {
                //判斷當前嘗試釋放鎖的線程,是不是擁有獨佔鎖的線程,若是不是拋出IllegalMonitorStateException異常
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                //將其鎖的狀態值減去要釋放的獨佔鎖的個數 
                int nextc = getState() - releases;
                //若是nextc爲0,表示獨佔鎖是否成功
                boolean free = exclusiveCount(nextc) == 0;
                if (free)
                    //若是鎖釋放成功,將其記錄擁有獨佔鎖的線程的記錄置爲空
                    setExclusiveOwnerThread(null);
                //設置鎖的狀態 
                setState(nextc);
                //返回獨佔鎖釋放是否成功 
                return free;
    }
    
    複製代碼

7、共享鎖

  1. 共享鎖的獲取

    //獲取共享鎖,不響應中斷,不會拋出中斷異常
    public final void acquireShared(int arg) {
            //當前線程調用tryAcquireShared嘗試去獲取共享鎖,若是返回值小於0表示獲取共享鎖失敗
            if (tryAcquireShared(arg) < 0)
                // 調用doAcquireShared方法去獲取共享鎖,tryAcquireShared、doAcquireShared方法會在下面詳細進行介紹
                doAcquireShared(arg);
    
    }
    
    
    //嘗試獲取共享鎖,AQS的模板方法,由具體的子類進行實現
    protected int tryAcquireShared(int arg) {
            //拋出UnsupportedOperationException異常
            throw new UnsupportedOperationException();
    }
    
    //ReentrantReadWriteLock類對tryAcquireShared方法的實現,會在ReentrantReadWriteLock源碼的分析中進行詳細的介紹
    protected final int tryAcquireShared(int unused) {
                //獲取當前線程
                Thread current = Thread.currentThread();
                //獲取鎖的狀態 
                int c = getState();
                //exclusiveCount根據鎖的狀態獲取獨佔鎖的個數若是不等於0,而且擁有此獨佔鎖的線程不是當前線程,直接返回-1失敗
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return -1;
                //根據鎖的狀態獲取共享鎖的個數 
                int r = sharedCount(c);
                //獲取共享鎖,當前線程是否須要阻塞,readerShouldBlock方法分爲公平鎖和非公平鎖的不一樣實現,公平鎖會調用hasQueuedPredecessors方法,判斷同步隊列中前面是否有節點,有阻塞,非公平鎖會
                //調用apparentlyFirstQueuedIsExclusive方法,判斷頭節點的狀態是不是獨佔鎖模式,若是是阻塞當前線程,不然繼續執行。而且共享鎖的個數得小於MAX_COUNT 
                if (!readerShouldBlock() &&
                    r < MAX_COUNT &&
                    //使用cas將當前鎖的狀態加上65535,即高16位存放共享鎖的個數
                    compareAndSetState(c, c + SHARED_UNIT)) {
                    //若是原先共享鎖的個數爲0
                    if (r == 0) {
                        //將當前線程賦值給第一個獲取共享鎖的線程firstReader 
                        firstReader = current;
                        //當前線程持有的共享鎖個數
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {//鎖的狀態共享鎖原先就有被獲取,而且第一個持有的線程是當前線程,firstReaderHoldCount++操做,持有共享鎖個數加1操做
                        //第一個獲取共享鎖的線程持有的共享鎖個數加1操做
                        firstReaderHoldCount++;
                    } else {
                        //獲取上一次緩存的線程的HoldCounter,HoldCounter實例是存放一個線程已獲取的共享鎖個數,及線程id
                        HoldCounter rh = cachedHoldCounter;
                        //上一次緩存的HoldCounter實例爲空,或者HoldCounter實例裏的線程id和當期線程id不相等
                        if (rh == null || rh.tid != getThreadId(current))
                            //從新獲取當前線程對應的HoldCounter實例
                            cachedHoldCounter = rh = readHolds.get();
                        //若是當前線程對應的HoldCounter實例的線程獲取共享鎖的個數爲0,從新將rh設置到ThreadLocal,ThreadLocal不清楚的能夠看下個人另外一篇對此的源碼分析
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        //不然線程對應的HoldCounter實例的線程已獲取的共享鎖個數進行加1操做 
                        rh.count++;
                    }
                    //返回1,表示獲取共享鎖成功
                    return 1;
                }
                //fullTryAcquireShared能夠看下面對此方法的介紹 
                return fullTryAcquireShared(current);
    }
    
    //ReentrantReadWriteLock類的fullTryAcquireShared方法,詳細的會再ReentrantReadWriteLock源碼分析進行介紹
    final int fullTryAcquireShared(Thread current) {
                HoldCounter rh = null;
                //死循環的獲取共享鎖 
                for (;;) {
                    //獲取鎖的狀態 
                    int c = getState();
                    //若是當前鎖狀態是獨佔鎖,而且擁有獨佔鎖的線程不是當前線程直接返回-1失敗
                    if (exclusiveCount(c) != 0) {
                        if (getExclusiveOwnerThread() != current)
                            return -1;
                      //當前線程是否須要阻塞,readerShouldBlock方法分爲公平鎖和非公平鎖的不一樣實現,公平鎖會調用hasQueuedPredecessors方法,判斷同步隊列中前面是否有節點,有阻塞,非公平鎖會調用apparentlyFirstQueuedIsExclusive方法,判斷頭節點的狀態是不是獨佔鎖模式,若是是阻塞當前線程 
                    } else if (readerShouldBlock()) {
                        //若是當前線程就是第一個獲取共享鎖的線程,不作任何操做 
                        if (firstReader == current) {
                            // assert firstReaderHoldCount > 0;
                        } else {
                            if (rh == null) {
                                //獲取上一次緩存的HoldCounter實例
                                rh = cachedHoldCounter;
                                //HoldCounter實例爲空,而且HoldCounter實例不屬於當前線程
                                if (rh == null || rh.tid != getThreadId(current)) {
                                    //獲取當前線程對應的HoldCounter實例 
                                    rh = readHolds.get();
                                    //若是當前線程獲取共享鎖個數爲0,將HoldCounter實例從ThreadLocal中移除 
                                    if (rh.count == 0)
                                        readHolds.remove();
                                }
                            }
                            //若是當前線程對應的HoldCounter實例的屬性count等於0,即當前線程沒有獲取到共享鎖,count當前線程獲取的共享鎖個數
                            if (rh.count == 0)
                                //返回-1失敗
                                return -1;
                        }
                    }
                    //當前共享鎖的個數大於MAX_COUNT,直接拋出一個錯誤
                    if (sharedCount(c) == MAX_COUNT)
                        throw new Error("Maximum lock count exceeded");
                    //共享鎖是使用狀態的高16位進行存儲,爲此加共享鎖加65535
                    if (compareAndSetState(c, c + SHARED_UNIT)) {
                        //若是共享鎖的個數爲0,即沒有獲取過共享鎖 
                        if (sharedCount(c) == 0) {
                            //將第一個獲取共享鎖的標識屬性firstReader賦值爲當前線程 
                            firstReader = current;
                            //獲取共享鎖的個數爲1
                            firstReaderHoldCount = 1;
                           //鎖的狀態共享鎖原先就有被獲取,而且第一個持有的線程是當前線程,firstReaderHoldCount++操做,持有共享鎖個數加1操做
                        } else if (firstReader == current) {
                            firstReaderHoldCount++;
                        } else {
                            //若是HoldCounter實例爲空
                            if (rh == null)
                                //從緩存中獲取上一次的HoldCounter實例
                                rh = cachedHoldCounter;
                            //HoldCounter實例爲空,而且不屬於當前線程 
                            if (rh == null || rh.tid != getThreadId(current))
                                //從ThreadLocal中從新獲取HoldCounter實例 
                                rh = readHolds.get();
                            //若是當前線程對應的HoldCounter實例的線程獲取共享鎖的個數爲0,從新將rh設置到ThreadLocal,ThreadLocal不清楚的能夠看下個人另外一篇對此的源碼分析
                            else if (rh.count == 0)
                                readHolds.set(rh);
                            //不然線程對應的HoldCounter實例的線程已獲取的共享鎖個數進行加1操做 
                            rh.count++;
                            //將緩存賦值爲當前線程的HoldCounter
                            cachedHoldCounter = rh; // cache for release
                        }
                        //返回1表示獲取共享鎖成功
                        return 1;
                    }
                }
    }
    
    //死循環獲取共享鎖,根據當前節點的前一個節點狀態來判斷當前線程是否應該阻塞,直到獲取到共享鎖
    private void doAcquireShared(int arg) {
            //往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
            final Node node = addWaiter(Node.SHARED);
            //獲取共享鎖是否成功
            boolean failed = true;
            try {
                //當前線程在獲取共享鎖的過程當中是否被中斷的標誌位
                boolean interrupted = false;
                for (;;) {
                    //獲取當前節點的前一個節點 
                    final Node p = node.predecessor();
                    //若是當前節點的前置節點爲表頭
                    if (p == head) {
                        //使用上面介紹的tryAcquireShared嘗試獲取共享鎖 
                        int r = tryAcquireShared(arg);
                        //
                        if (r >= 0) {
                            //能夠看下面對setHeadAndPropagate方法的介紹
                            setHeadAndPropagate(node, r);
                            //將當前節點的前置節點下一個節點置爲空
                            p.next = null; // help GC
                            //若是發生中斷請求
                            if (interrupted)
                                selfInterrupt();
                            //獲取共享鎖成功
                            failed = false;
                            //直接返回 
                            return;
                        }
                    }
                    //判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        //parkAndCheckInterrupt返回值是否有中斷請求
                        interrupted = true;
                }
            } finally {
                //若是失敗
                if (failed)
                    //將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹
                    cancelAcquire(node);
            }
    }
    
    // 從新設置CLH隊列頭,若是CLH隊列頭的下一個節點爲null或者共享模式,那麼就要喚醒共享鎖上等待的線程
    private void setHeadAndPropagate(Node node, int propagate) {
            //獲取同步隊列的頭節點
            Node h = head; // Record old head for check below
            //將傳入進來的節點設置爲同步隊列的表頭,將傳入進來的前置節點和線程都置爲空
            setHead(node);
            if (propagate > 0 || h == null || h.waitStatus < 0 ||
                (h = head) == null || h.waitStatus < 0) {
                // 獲取新的CLH隊列頭的下一個節點s
                Node s = node.next;
                // 若是節點s是空或者共享模式節點,那麼就要喚醒共享鎖上等待的線程
                if (s == null || s.isShared())
                    //在下面共享鎖的釋放會對此方法進行介紹 
                    doReleaseShared();
            }
    }
    
    //若是當前線程在獲取共享鎖的過程當中,有其餘線程調用當前線程的interrupt方法,中斷請求,會拋出中斷異常
    public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
            //若是當前線程被其餘線程發起中斷請求 
            if (Thread.interrupted())
                //拋出中斷異常
                throw new InterruptedException();
            //tryAcquireShared能夠看上面對此方法的介紹
            if (tryAcquireShared(arg) < 0)
                //能夠看下面對doAcquireSharedInterruptibly的介紹
                doAcquireSharedInterruptibly(arg);
    }
    
    //超時的獲取共享鎖,而且響應中斷請求,拋出中斷異常
    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
            //若是當前線程被其餘線程發起中斷請求 
            if (Thread.interrupted())
                //拋出中斷異常
                throw new InterruptedException();
            //tryAcquireShared能夠看上面對此方法的介紹
            return tryAcquireShared(arg) >= 0 ||
                //能夠看下面對doAcquireSharedNanos的介紹
                doAcquireSharedNanos(arg, nanosTimeout);
    }
    
    private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
            //往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
            final Node node = addWaiter(Node.SHARED);
            //執行是否失敗的標誌位,若是失敗會將此節點從同步隊列中移除
            boolean failed = true;
            try {
                //死循環的獲取共享鎖,除非獲取共享鎖成功,獲取線程在阻塞的過程當中,被中斷,拋出中斷異常
                for (;;) {
                    //獲取當前節點的前一個節點 
                    final Node p = node.predecessor();
                    //若是當前節點的前置節點爲表頭 
                    if (p == head) {
                        //使用上面介紹的tryAcquireShared嘗試獲取共享鎖 
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            //能夠看上面對setHeadAndPropagate方法的介紹
                            setHeadAndPropagate(node, r);
                            //將當前節點的前置節點下一個節點置爲空
                            p.next = null; // help GC
                            //獲取共享鎖成功
                            failed = false;
                            //直接返回 
                            return;
                        }
                    }
                    //判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹 
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        //若是線程在阻塞的過程當中,有其餘線程調用當前線程的interrupt方法,中斷請求,拋出中斷異常
                        throw new InterruptedException();
                }
            } finally {
                //若是失敗 
                if (failed)
                    //將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹 
                    cancelAcquire(node);
            }
    }
    
    //支持中斷,會拋出中斷異常,返回值是否獲取共享鎖成功
    private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
            //若是傳入進來的超時時間小於等於0直接返回失敗
            if (nanosTimeout <= 0L)
                return false;
            //死亡時間,當前時間加上超市時間 
            final long deadline = System.nanoTime() + nanosTimeout;
            //往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
            final Node node = addWaiter(Node.SHARED);
            //執行是否失敗的標誌位,若是失敗會將此節點從同步隊列中移除
            boolean failed = true;
            try {
                for (;;) {
                    //獲取當前節點的前一個節點 
                    final Node p = node.predecessor();
                    //若是當前節點的前置節點爲表頭 
                    if (p == head) {
                        //使用上面介紹的tryAcquireShared嘗試獲取共享鎖 
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            //能夠看上面對setHeadAndPropagate方法的介紹
                            setHeadAndPropagate(node, r);
                           //將當前節點的前置節點下一個節點置爲空
                            p.next = null; // help GC
                            //獲取共享鎖成功
                            failed = false;
                            //直接返回 
                            return;
                        }
                    }
                    //獲取剩餘的超時時間
                    nanosTimeout = deadline - System.nanoTime();
                    //若是在超時時間仍是沒有獲取到共享鎖,直接返回失敗 
                    if (nanosTimeout <= 0L)
                        return false;
                    //判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹 
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        nanosTimeout > spinForTimeoutThreshold) //而且超時時間大於必定的閾值不然讓其自旋一段時間
                        //使用LockSupport阻塞當前線程
                        LockSupport.parkNanos(this, nanosTimeout);
                    //若是當前線程在阻塞過程當中被中斷
                    if (Thread.interrupted())
                        //直接拋出中斷異常 
                        throw new InterruptedException();
                }
            } finally {
                //若是失敗 
                if (failed)
                    //將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹 
                    cancelAcquire(node);
            }
    }
    複製代碼

  2. 共享鎖的釋放

    //釋放共享鎖
    public final boolean releaseShared(int arg) {
        //嘗試釋放共享鎖
        if (tryReleaseShared(arg)) {
            //喚醒等待共享鎖的線程
            doReleaseShared();
            return true;
        }
        return false;
    }                        
    
    //嘗試去釋放共享鎖,AQS的模板方法,由不一樣的子類進行實現
    protected boolean tryReleaseShared(int arg) {
        throw new UnsupportedOperationException();
    }
    
    //ReentrantReadWriteLock類的tryReleaseShared方法實現
    protected final boolean tryReleaseShared(int unused) {
                //獲取當前線程 
                Thread current = Thread.currentThread();
    			//若是當前線程是第一個獲取共享鎖的線程 
                if (firstReader == current) {
                    // assert firstReaderHoldCount > 0;
    				//第一個獲取共享鎖的線程持有的共享鎖數等於1,將firstReader置爲空 
                    if (firstReaderHoldCount == 1)
                        firstReader = null;
                    else
    				    //第一個獲取共享鎖的線程持有的共享鎖數作減1操做
                        firstReaderHoldCount--;
                } else {
    			    //獲取上一次緩存的HoldCounter實例
                    HoldCounter rh = cachedHoldCounter;
    				//HoldCounter實例rh爲空,或者rh不屬於當前線程
                    if (rh == null || rh.tid != getThreadId(current))
    				    //從新獲取當前線程的HoldCounter實例
                        rh = readHolds.get();
    				//若是當前線程持有的共享鎖個數 
                    int count = rh.count;
                    if (count <= 1) {
    				    //從ThreadLocal中移除當前線程的HoldCounter實例 
                        readHolds.remove();
    					//count <= 0表示當前線程就沒有獲取到讀鎖(共享鎖),這裏釋放就拋出異常
                        if (count <= 0)
                            throw unmatchedUnlockException();
                    }
    				//當前線程的持有共享鎖個數作減1操做
                    --rh.count;
                } 
    			//死循環的釋放鎖,若是當前鎖的共享鎖個數爲0,返回true,代表共享鎖釋放成功
                for (;;) {
                    int c = getState();
                    int nextc = c - SHARED_UNIT;
                    if (compareAndSetState(c, nextc))
                        return nextc == 0;
                }
    }
    
    //喚醒等待共享鎖的線程
    private void doReleaseShared() {
            for (;;) {
                // 將同步隊列頭賦值給節點h
                Node h = head;
                // 若是節點h不爲null,且不等於同步隊列尾
                if (h != null && h != tail) {
                    // 獲得節點h的狀態
                    int ws = h.waitStatus;
                    //若是狀態是Node.SIGNAL,就要喚醒節點h後繼節點的線程
                    if (ws == Node.SIGNAL) {
                        // 將節點h的狀態設置成0,若是設置失敗,就繼續循環,再試一次。
                        if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                            continue;
                        // 喚醒節點h後繼節點的線程
                        unparkSuccessor(h);
                    }
                    // 若是節點h的狀態是0,就設置ws的狀態是PROPAGATE。
                    else if (ws == 0 &&
                             !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                        continue;                // loop on failed CAS
                }
                // 若是同步隊列頭head節點發生改變,繼續循環,
                // 若是沒有改變,就跳出循環
                if (h == head)
                    break;
            }
    }複製代碼
相關文章
相關標籤/搜索