AbstractQueuedSynchronizer (二):獨(dú)占模式 ReentrantLock

ReentrantLock 實(shí)現(xiàn)了隱式鎖synchronized基本的行為和語義默垄,并且提供了額外的一些能力。

一個(gè)ReentrantLock被最后一次成功獲取到鎖的線程持有怠益,直到線程釋放他呛伴。
可重入的意思是一個(gè)線程如果成功調(diào)用lock()方法并且返回,
成功的獲取了鎖盔憨,當(dāng)前線程未釋放鎖時(shí),如果當(dāng)前線程再次獲取鎖將會(huì)立即返回讯沈。
在調(diào)用線程內(nèi)部可以使用isHeldByCurrentThread檢查是是否被當(dāng)前線程持有郁岩。
通過getHoldCount查看當(dāng)前線程持有鎖有多少個(gè)狀態(tài),即重入次數(shù)。
ReentrantLock有公平和非公平兩種问慎,即獨(dú)占模式也分為兩種萍摊。ReentrantLock內(nèi)部類中分別都對(duì)其進(jìn)行了實(shí)現(xiàn)。
默認(rèn)構(gòu)造函數(shù)是非公平模式如叼,也可通過傳入可選的參數(shù)指定公平實(shí)現(xiàn)冰木。公平模式下鎖更偏向?qū)?zhí)行權(quán)授予最長(zhǎng)-等待線程。
非公平模式下不保證任何訪問順序笼恰。
公平模式下的鎖具有更低的吞吐量(通常來說就是很慢)比非公平鎖踊沸,但是這樣保證了用較少時(shí)間上的差異來獲得鎖以及保護(hù)線程不會(huì)饑餓。
注意:公平鎖不保證線程調(diào)度的公平性挖腰,因此,多個(gè)線程使用同一把鎖练湿,其中一個(gè)線程可能獲取成功了多次而其他活動(dòng)線程還沒什么進(jìn)展也也沒持有鎖猴仑。
這句話的意思是盡管當(dāng)前線程多次獲取鎖經(jīng)歷了排隊(duì)等待這些過程,但是依然完成了任務(wù)并且成功獲取了多次鎖肥哎,說明被線程調(diào)度到了辽俗,而其他活動(dòng)的線程的任務(wù)沒有進(jìn)展,盡管他們不需要鎖篡诽,這是由于線程調(diào)度導(dǎo)致的崖飘。
同樣注意沒有時(shí)間參數(shù)的tryLock()方法也不滿足公平性。盡管有其他線程在等待杈女,如果他獲取的時(shí)候這個(gè)鎖是空閑的朱浴,仍然會(huì)獲取成功。因?yàn)閠ryLock直接調(diào)用的是nonfairTryAcquire达椰。

ReentrantLock有三個(gè)內(nèi)部類:

Sync:鎖的基類實(shí)現(xiàn)繼承AQS翰蠢,子類實(shí)現(xiàn)是下面的公平鎖FairSync和鎖NonfairSync
FairSync:公平鎖實(shí)現(xiàn)
NonfairSync:非公平鎖實(shí)現(xiàn)
  abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**非公平的tryLock。tryAcquire被子類實(shí)現(xiàn)啰劲,但是tryLock和tryAcquire都需要nonfair所以放在基類中梁沧,這樣即便指定模式是公平鎖,其tryLock也是非公平的
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //獲取AQS狀態(tài)蝇裤,getState 具有volatile讀語義
            int c = getState();
            //c=0 表示鎖是空閑的
            if (c == 0) {
                //原子性的修改狀態(tài)為acquires(共享資源)廷支,acquires根據(jù)實(shí)現(xiàn)不同而表現(xiàn)不同,在ReentrantLock 0表示空閑大于1表示已經(jīng)被獲取和重入的次數(shù)栓辜,在semaphore表現(xiàn)為共享資源的數(shù)量恋拍。
                if (compareAndSetState(0, acquires)) {
                    //成功設(shè)置排他擁有線程為當(dāng)前線程
                    setExclusiveOwnerThread(current);
                    //成功直接返回表示直接獲取到鎖
                    return true;
                }
            }
            //已經(jīng)獲取到鎖則增加重入次數(shù)并立即返回:這就是被稱為重入鎖的原因
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
     static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
        、**首先進(jìn)行l(wèi)ock 藕甩。失敗則調(diào)用AQS的acquire芝囤,acquire會(huì)調(diào)用NonfairSync#tryAcquire最后調(diào)用nonfairTryAcquire
         * 可以發(fā)現(xiàn)非公平鎖首先進(jìn)行了兩次的lock,如果成功則直接返回。不會(huì)經(jīng)過入隊(duì)悯姊,park羡藐,unpark線程上下文切換,這是是非公平鎖快的原因悯许。
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

     /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        
        final void lock() {
            //直接調(diào)用父類的acquire仆嗦,acquire首先調(diào)用FairSync#tryAcquire
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //與非公平鎖不同的是公平鎖首先會(huì)判斷是否有線程已經(jīng)在排隊(duì)等待,沒有才會(huì)直接嘗試修改狀態(tài)先壕。
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }
//AbstractQueuedSynchronizer#hasQueuedPredecessors
       /**
         查詢是否已經(jīng)有線程在排隊(duì)瘩扼,并且等待時(shí)間比當(dāng)前線程長(zhǎng)
         調(diào)用這個(gè)方法等價(jià)于 (但是這個(gè)方法可能更有效率)getFirstQueuedThread() != Thread.currentThread() &&hasQueuedThreads()
         注意:因?yàn)榫€程中斷和超時(shí)可能發(fā)生在任何時(shí)候,返回true垃僚,即隊(duì)列中有線程集绰,但是其他線程也可能在當(dāng)前線程之前進(jìn)行aquire操作
              返回false,即隊(duì)列為空谆棺,也有可能其他線程在這個(gè)線程之前進(jìn)行了入隊(duì)操作
        這個(gè)方法被設(shè)計(jì)成公平鎖去避免沖突栽燕。一個(gè)同步器的方法應(yīng)該返回false,tryAcquireShared應(yīng)該返回一個(gè)負(fù)數(shù)改淑,如果這個(gè)方法返回true(除非他是一個(gè)重入的acquire操作)碍岔。
        例如tryAcquire方法在一個(gè)公平的可重入的獨(dú)占鎖應(yīng)該像下面這種形式(和ReentrantLock#FairSync#tryAcquire語義一抹一樣):
            * protected boolean tryAcquire(int arg) {
     *   if (isHeldExclusively()) {
     *     // A reentrant acquire; increment hold count
     *     return true;
     *   } else if (hasQueuedPredecessors()) {
     *     return false;
     *   } else {
     *     // try to acquire normally
     *   }
     * }}</pre>
     * 返回 true:如果當(dāng)前線程前有排隊(duì)的線程
           false:如果當(dāng)前線程時(shí)隊(duì)列的頭部或者隊(duì)列是空的
       **/
       public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        //1、h !=t 只有當(dāng)隊(duì)列尚未被初始化朵夏,AQS被初始化蔼啦,head和tail都沒被賦值時(shí)返回false,即非公平鎖第一次進(jìn)入tryAquire仰猖,hasQueuedPredecessors返回false捏肢,接著tryAquire調(diào)用compareAndSetState成功。
         //第二個(gè)線程進(jìn)入 同樣hasQueuedPredecessors返回false饥侵,compareAndSetState失敗猛计,調(diào)用addWaiter,初始化head和tail爆捞,head和tail都不相等奉瘤。
         /**
           2、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s不為空煮甥,并且s不是當(dāng)前線程盗温。代表頭節(jié)點(diǎn)執(zhí)行完后s節(jié)點(diǎn)有可能被執(zhí)行。當(dāng)前線程無法參與競(jìng)爭(zhēng)成肘,所以返回true卖局。這種情況發(fā)生在當(dāng)前節(jié)點(diǎn)是第一次入隊(duì)的情況。
           3双霍、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s不為空砚偶,并且s是當(dāng)前線程批销。代表頭節(jié)點(diǎn)執(zhí)行完后s節(jié)點(diǎn)(當(dāng)前線程)有可能被執(zhí)行所以返回fasle。(代表上一層可以去競(jìng)爭(zhēng)獨(dú)占狀態(tài))染坯。這種情況發(fā)生在當(dāng)前節(jié)點(diǎn)已經(jīng)入隊(duì)的情況下均芽。
           4、當(dāng)頭結(jié)點(diǎn)和尾節(jié)點(diǎn)不相等并且 如果head節(jié)點(diǎn)的next節(jié)點(diǎn)s為空单鹿,那么直接返回true掀宋,代表頭節(jié)點(diǎn)后面沒有節(jié)點(diǎn)。即當(dāng)前線程不是頭節(jié)點(diǎn)的next節(jié)點(diǎn)仲锄。返回true劲妙。不直接參與競(jìng)爭(zhēng),這種情況發(fā)生在(有可能頭節(jié)點(diǎn)后面的節(jié)點(diǎn)被取消儒喊,或者新入隊(duì)的節(jié)點(diǎn)next尚未賦值)
         **/
        return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
    }
     總結(jié)下這個(gè)方法:以上四點(diǎn)保證了如果有其他的線程在頭節(jié)點(diǎn)的next上等待并且head節(jié)點(diǎn)的next節(jié)點(diǎn)不是當(dāng)前節(jié)點(diǎn)時(shí)镣奋,那么這個(gè)線程不能直接參與競(jìng)爭(zhēng),只能加入同步隊(duì)列怀愧,否則如果當(dāng)前head節(jié)點(diǎn)的next節(jié)點(diǎn)指向自己侨颈,將直接執(zhí)行compareAndset設(shè)置狀態(tài)。
                   這樣保證了除第一個(gè)線程外其他線程都必須經(jīng)過排隊(duì)等待head的next指向自己掸驱,所以要實(shí)現(xiàn)公平鎖的首要條件就是使用hasQueuedPredecessors 作為判斷條件之一肛搬。

總結(jié)下:
1没佑、公平鎖和非公平鎖最大的差異在tryAcquire是否會(huì)檢查隊(duì)列中是否有線程在等待
2毕贼、非平鎖首先會(huì)嘗試修改2次,進(jìn)行搶占而不管是否已經(jīng)有線程在排隊(duì)蛤奢。
3鬼癣、公平鎖的第一個(gè)線程將會(huì)被直接獲取到鎖執(zhí)行,當(dāng)且僅當(dāng)?shù)谝粋€(gè)線程沒有執(zhí)行完畢啤贩,第二個(gè)線程才會(huì)進(jìn)入排隊(duì)待秃。執(zhí)行addWaiter和acquireQueued
先順著acquire方法分析下去,然后再逐個(gè)分析ReentrantLock的方法痹屹。

``` /**
        只能在獨(dú)占模式下使用acquire方法(因?yàn)閍ddWaiter傳入的mode是exclusive章郁,忽略中斷)。并且至少調(diào)用一次tryAcquire志衍。
        調(diào)用acquire成功的話會(huì)立即返回否則暖庄,線程會(huì)被入隊(duì),
        可能重復(fù)的阻塞和解阻塞楼肪,調(diào)用tryAcquire直到成功培廓。(第一次進(jìn)來無法獲取鎖,阻塞春叫。后面有可能其他節(jié)點(diǎn)線程獲取鎖發(fā)生異常肩钠,cancelAquire會(huì)調(diào)用unparkSuccessor泣港,
        當(dāng)前節(jié)點(diǎn)有可能被喚醒,判斷head不是自己前驅(qū)价匠,進(jìn)行取消節(jié)點(diǎn)裁剪后当纱,則再次阻塞,直到head是自己的前驅(qū)并且調(diào)用release方法重置狀態(tài)霞怀,喚醒自己惫东,線程再次被喚醒)
        這個(gè)方法可以用來實(shí)現(xiàn)Lock接口的lock語義
     **/
     public final void acquire(int arg) {
        //tryAcquire失敗后添加到隊(duì)列末尾并且排隊(duì)等待,如果tryAcquire成功立即返回毙石,表示成功獲取到鎖廉沮。
        //tryAcquire失敗:1.head的next沒有指向當(dāng)前線程徐矩,hasQueuedPredecessors返回false 滞时。
        //2.如果tryAcquire返回true,acquire立即返回 2.無線程排隊(duì)滤灯,hasQueuedPredecessors返回false坪稽。
        //前一個(gè)線程未釋放狀態(tài),compareAndSetState失敗鳞骤,tryAcquire返回false窒百,這才開始第一次入隊(duì)酥泛。
        
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    總結(jié):tryAcquire成功將立即返回獲取到鎖僻肖,失敗則進(jìn)行排隊(duì)。下面說下tryAcquire成功失敗的幾種情況:
    tryAcquire成功:
        1逆航、鎖剛剛新建完成初始化美旧,第一個(gè)線程來請(qǐng)求鎖渤滞,毫無疑問 hasQueuedPredecessors中 head=null,tail=null 榴嗅,hasQueuedPredecessors中h != t返回false妄呕,tryAcquire調(diào)用compareAndSet成功獲取到鎖。
        2嗽测、檔head節(jié)點(diǎn)的next指向一個(gè)節(jié)點(diǎn)绪励,這個(gè)節(jié)點(diǎn)hasQueuedPredecessors返回false,因?yàn)樽约壕褪堑鹊米罹玫?唠粥,于是不停的調(diào)用tryAcquire疏魏,獲取到鎖。
    tryAcquire失斕啊:
        1蠢护、新線程加入:判斷hasQueuedPredecessors為true,加入等待隊(duì)列進(jìn)行等待养涮。
        2葵硕、等待隊(duì)列中的線程雖然head的next節(jié)點(diǎn)指向自己?jiǎn)紊韈ompareAndset設(shè)置失敗眉抬。
        
    //添加新的節(jié)點(diǎn)到等待隊(duì)列中      
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        //快速嘗試入隊(duì),否則使用自旋入隊(duì)
        //將tail復(fù)制給pred
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            //設(shè)置尾節(jié)點(diǎn)為node
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);//確保隊(duì)列為空的情況下
        return node;
    }
    //自旋入隊(duì)操作,
     private Node enq(final Node node) {
        for (;;) {
            //第一個(gè)節(jié)點(diǎn)首次入隊(duì)首先執(zhí)行懈凹,初始化空節(jié)點(diǎn)
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //入隊(duì)
                node.prev = t;//首先保證將前驅(qū)節(jié)點(diǎn)賦值給prev蜀变,保證前驅(qū)穩(wěn)定。所以在遍歷next=null情況下使用prev向前遍歷是安全可靠的介评。
                if (compareAndSetTail(t, node)) {
                    t.next = node;//這一步操作是库北,非線程安全 可能節(jié)點(diǎn)已經(jīng)在隊(duì)列上了 t.next仍然為null,對(duì)其他線程不可見
                    return t;
                }
            }
        }
    }
    總結(jié)下:enq在第二個(gè)線程入隊(duì)時(shí)才延遲初始化head節(jié)點(diǎn)和當(dāng)且線程節(jié)點(diǎn)们陆。后續(xù)入隊(duì)操作直接執(zhí)行else后面的操作寒瓦,并且t.next = node 不能保證已經(jīng)入隊(duì)的節(jié)點(diǎn)next不為null,這也是hasQueuedPredecessors判斷next==null的原因之一坪仇。
       /**
     * Convenience method to interrupt current thread.設(shè)置中斷狀態(tài)
     */
    static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }
        /**
            在獨(dú)占且不可中斷模式下已經(jīng)排隊(duì)的節(jié)點(diǎn)acquire方法杂腰。
            同樣也被用于條件等待方法await
        **/
        final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                //判斷當(dāng)前節(jié)點(diǎn)的前驅(qū)是否是頭節(jié)點(diǎn),是才進(jìn)行tryAcquire調(diào)用子類的方法去判斷并修改狀態(tài)椅文,且成功后設(shè)置隊(duì)列Head為當(dāng)節(jié)點(diǎn)并且將head節(jié)點(diǎn)出隊(duì)喂很。
                //當(dāng)且僅當(dāng)當(dāng)前線程被喚醒后,重新循環(huán)皆刺,判斷p==head==true少辣,再進(jìn)行tryAquire
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;//標(biāo)記失敗狀態(tài)
                    return interrupted;//acquire 中根據(jù)返回的中斷狀態(tài)設(shè)置值當(dāng)前線程的中斷。 
                }
                //設(shè)置signal狀態(tài)羡蛾,在下次自旋中判斷返回true漓帅,調(diào)用parkAndCheckInterrupt設(shè)置中斷狀態(tài),并park林说。
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                     //執(zhí)行到這里表明已經(jīng)被前驅(qū)節(jié)點(diǎn)喚醒煎殷,并繼續(xù)自旋獲取鎖
                    //如果被中斷設(shè)置中斷狀態(tài)屯伞,但是并不處理
                    interrupted = true;
            }
        } finally {
            //
            if (failed)
                cancelAcquire(node);
        }
    }
     /**
     檢查和更新acquire失敗的節(jié)點(diǎn)的狀態(tài)腿箩,如果一個(gè)節(jié)點(diǎn)應(yīng)該阻塞則返回true。
     主要控制acquireQueued的死循環(huán)劣摇。
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        //已經(jīng)設(shè)置了前驅(qū)節(jié)點(diǎn)的珠移,SIGNAL 直接返回true,park這個(gè)線程
        if (ws == Node.SIGNAL)
           
            return true;
        if (ws > 0) {
            /* 
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             * 前驅(qū)節(jié)點(diǎn)已經(jīng)被設(shè)置為取消狀態(tài)末融,需要修改prev節(jié)點(diǎn)钧惧,這里 有幾個(gè)問題
             * 1、為什么是在這里修改勾习? 因?yàn)樵诰€程即將進(jìn)入park的時(shí)候需要保證自己能被喚醒,通常是誰喚醒自己呢浓瞪?
                前驅(qū)節(jié)點(diǎn),但是不總是前驅(qū)節(jié)點(diǎn)巧婶。所以需要保證前驅(qū)節(jié)點(diǎn)是活著的乾颁。這里僅僅是嘗試涂乌,就算重新設(shè)置了前驅(qū)節(jié)點(diǎn),
                設(shè)置后的前驅(qū)節(jié)點(diǎn)也會(huì)發(fā)生異常而取消英岭,所以在喚醒的時(shí)候還會(huì)有一次查找判斷
             * 2湾盒、為什么在取消的時(shí)候修改了一次prev,next屬性這里還要設(shè)置一次诅妹?
                 next屬性已經(jīng)由線程取消的時(shí)候被設(shè)置了罚勾,發(fā)生在這個(gè)步驟前。cancelAcquire方法可以同時(shí)被多個(gè)方法調(diào)用發(fā)送競(jìng)爭(zhēng)吭狡,所以要使用CAS修改尖殃,但是不保證一定成功。所以在每個(gè)線程之中需要再進(jìn)行保證划煮。
             * 3分衫、修改其他節(jié)點(diǎn)的prev,next屬性是線程安全的嗎般此?
                 是的蚪战。進(jìn)入這個(gè)方法時(shí)判斷的是node節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)的狀態(tài)。假設(shè)這個(gè)節(jié)點(diǎn)的前面也有個(gè)node判斷前驅(qū)節(jié)點(diǎn)是取消狀態(tài)铐懊,然后嘗試修改邀桑。那么這個(gè)節(jié)點(diǎn)的線程找到的是他的前驅(qū)節(jié)點(diǎn)的前面的第一個(gè)沒有被取消的節(jié)點(diǎn)。
                 并不是我們這個(gè)線程所找到的第一個(gè)未取消的節(jié)點(diǎn)科乎,如果本節(jié)點(diǎn)后面有線程在檢查也一樣壁畸,最終大家都只負(fù)責(zé)修改自己的前驅(qū),刪除掉的是自己那一塊區(qū)域茅茂,所以并不會(huì)發(fā)生競(jìng)爭(zhēng)捏萍。
                 總結(jié):觀察cancelAcquire和unparkSuccessor最終完成將取消節(jié)點(diǎn)出隊(duì)的都是這部分操作
                
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /* 獲取獨(dú)占鎖的線程在進(jìn)來的時(shí)候waitStatus都是0。表示這個(gè)線程需要設(shè)置信號(hào)空闲,
            然后在下一次自旋中被park令杈。下次自旋中仍然會(huì)查看是否自己是head節(jié)點(diǎn)是的話就嘗試修改狀態(tài)。這樣盡最大努力去嘗試然后再park
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
    //park 并且返回當(dāng)前線程是否被中斷
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
     /**
     * Cancels an ongoing attempt to acquire.
     *  取消正在進(jìn)行的acquire碴倾,cancelAcquire總是在finally語句塊中被調(diào)用
     *  發(fā)生異常進(jìn)行取消是基本算法的健壯性目標(biāo)之一逗噩。cancelAcquire 首先應(yīng)滿足,取消當(dāng)前節(jié)點(diǎn)后應(yīng)能不影響其他線程的執(zhí)行跌榔,也就是應(yīng)該喚醒下一個(gè)線程异雁。
     *并且應(yīng)該重新設(shè)置AQS隊(duì)列,將被取消的節(jié)點(diǎn)進(jìn)行清理僧须,以提高隊(duì)列的性能纲刀,因?yàn)樵趩拘岩粋€(gè)線程時(shí)也會(huì)首先判斷隊(duì)列的狀態(tài)并刪除取消的節(jié)點(diǎn)。
     *但是這一操作不應(yīng)該由釋放鎖的線程來做因?yàn)樗氖虑橐呀?jīng)做完了担平,清理隊(duì)列應(yīng)該由發(fā)生異常的線程進(jìn)行清理示绊。所以cancelAcquire總是在finally語句塊中芥挣。
     *
     * @param node the node
     */
    private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        //獲取到當(dāng)節(jié)點(diǎn)前第一個(gè)狀態(tài)沒有設(shè)置為取消的節(jié)點(diǎn),并且跳過取消的節(jié)點(diǎn)
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        // predNext is the apparent node to unsplice. CASes below will
        // fail if not, in which case, we lost race vs another cancel
        // or signal, so no further action is necessary. 
        //predNext 即為第一個(gè)找到的沒有設(shè)置為取消狀態(tài)的節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)耻台。

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;

        // If we are the tail, remove ourselves.
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);//完成一部分出隊(duì)空免,仍保留prev引用
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);//完成一部分出隊(duì),仍保留prev引用
            } else {
                //
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }
1.當(dāng)前節(jié)點(diǎn)是tail節(jié)點(diǎn)時(shí)設(shè)置tail為pred盆耽,自己未獲取到鎖蹋砚,不需要喚醒next節(jié)點(diǎn)。
注意:當(dāng)前節(jié)點(diǎn)不可能是head節(jié)點(diǎn)
2摄杂、pred是head節(jié)點(diǎn)時(shí)坝咐,node節(jié)點(diǎn)故障了直接喚醒他后面的線程 unparkSuccessor(node);unpark之后進(jìn)入aquiredQueued判斷當(dāng)前前驅(qū)是head(已經(jīng)設(shè)置node.prev=pred)成功。CAS的時(shí)候分為兩種情況:
 2.1 CAS成功:head恰好釋放鎖調(diào)用release方法析恢,當(dāng)然head線程也在unparkSuccessor觀察到head.next.waitStatus>0 墨坚,
 并且整個(gè)替換了,而不是只替換next屬性映挂。然后這個(gè)節(jié)點(diǎn)就變成了head節(jié)點(diǎn)泽篮,其實(shí)這就是正常的release流程。
 這里只是說明不管CAS成功還是失敗都不會(huì)影響到刪除取消的節(jié)點(diǎn)柑船,都是做的一樣的操作對(duì)結(jié)果本身沒有影響帽撑。
 在head線程刪除取消狀態(tài)的節(jié)點(diǎn)的時(shí)候,也只刪除離自己最近的節(jié)點(diǎn)鞍时,直到找到waitstatus<0 的節(jié)點(diǎn)亏拉。
 2.2 CAS失敗,因?yàn)槟嫖。谑沁M(jìn)入shouldParkAfterFailedAcquire及塘,由正常節(jié)點(diǎn)的線程去設(shè)置新的prev屬性和新前驅(qū)節(jié)點(diǎn)的后next屬性。因?yàn)槟菢幼鍪蔷€程安全的(查看shouldParkAfterFailedAcquire)锐极。
3笙僚、pred不是首節(jié)點(diǎn),當(dāng)前節(jié)點(diǎn)也不是tail溪烤。在pred的status為SIGNAL并且pred的thread不為空(判斷pred是否已經(jīng)取消)味咳,嘗試設(shè)置 pred的next指向 node的next屬性庇勃。
    這里都是使用的CAS不保證成功設(shè)置檬嘀。并且就算compareAndSetNext(pred, predNext, next);成功,也只是完成了刪除節(jié)點(diǎn)的一部分操作责嚷,prev屬性并沒有沒設(shè)置鸳兽。
    這里只是盡自己最大努力做一點(diǎn)事情,真正的將已經(jīng)取消節(jié)點(diǎn)(或者說完成一半出隊(duì))出隊(duì)發(fā)生在罕拂,unparkSuccessor的時(shí)候揍异,head節(jié)點(diǎn)會(huì)檢查next節(jié)點(diǎn)是否已經(jīng)取消全陨,最后將離自己最近的一些取消節(jié)點(diǎn)出隊(duì)。
4衷掷、為什么這里只設(shè)置next屬性辱姨,而不修改prev屬性呢?為什么會(huì)在這里設(shè)置next屬性呢戚嗅?
 我認(rèn)為有以下原因:
 1雨涛、prev被設(shè)計(jì)為可靠的屬性,在unparkSuccessor懦胞,shouldParkAfterFailedAcquire替久,cancelAcquire都在被遍歷,如果此時(shí)對(duì)prev進(jìn)行修改可能導(dǎo)致競(jìng)爭(zhēng)躏尉,喚醒線程蚯根、其他線程的取消都可能出問題。
 而在shouldParkAfterFailedAcquire已經(jīng)提到修改prev和next是按段修改的胀糜。每段都由一個(gè)線程負(fù)責(zé)颅拦,不會(huì)引起遍歷修改這樣的競(jìng)爭(zhēng)情況發(fā)生。假設(shè)shouldParkAfterFailedAcquire
 在修改的時(shí)候另外一個(gè)node正在unparkSuccessor教藻,并且這個(gè)node的next已經(jīng)被取消矩距,那么最終被unpark的線程也會(huì)執(zhí)行shouldParkAfterFailedAcquire,最終修改prev和next來釋放取消的節(jié)點(diǎn)怖竭。
 
 2锥债、只是盡最大努力修改
 
 總結(jié):cancelAcquire 只是設(shè)置取消狀態(tài),保證最大努力交付(設(shè)置next的值痊臭,設(shè)置prev整個(gè)隊(duì)列的狀態(tài)將受到影響)哮肚。真正做事的是shouldParkAfterFailedAcquire和unparkSuccessor,因?yàn)樗麅刹拍鼙WC這么做是安全的广匙。
      shouldParkAfterFailedAcquire直接進(jìn)行整個(gè)節(jié)點(diǎn)的賦值允趟,將取消節(jié)點(diǎn)踢出去,cancelAcquire只是設(shè)置next的值鸦致,或者交給shouldParkAfterFailedAcquire潮剪,shouldParkAfterFailedAcquire同時(shí)將prev和next都修改了。
      作用域:cancelAcquire作用于發(fā)生異常的node分唾,shouldParkAfterFailedAcquire入隊(duì)的等待的線程抗碰,unparkSuccessor 作用于喚醒當(dāng)前節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)的時(shí)候。
      所以: 應(yīng)該是是三個(gè)步驟 1.設(shè)置狀態(tài)(cancelAcquire) 2.shouldParkAfterFailedAcquire(park前檢查) 3.unparkSuccessor(unpark前檢查)绽乔。三步來減少取消節(jié)點(diǎn)對(duì)隊(duì)列性能的影響弧蝇。
```     //ReentrantLock#unlock
  public void unlock() {
       sync.release(1);
   }
   //AQS#release,獨(dú)占鎖釋放。
  public final boolean release(int arg) {
       if (tryRelease(arg)) {//首先由子類釋放狀態(tài)和OwnerThread
           Node h = head;//AQS 更關(guān)注的是隊(duì)列
           /**
           只有當(dāng)head不為空的情況下并且head的狀態(tài)不為0才喚醒繼任者線程。
           1看疗、h為空表明只有一個(gè)一個(gè)線程使用過鎖并且沒有發(fā)生任何競(jìng)爭(zhēng)沙峻,
             隊(duì)列的head和tail都沒初始化,直接返回true两芳,釋放成功摔寨。
             1.1當(dāng)這種情況發(fā)生時(shí)有第二個(gè)線程進(jìn)行爭(zhēng)搶鎖,hasQueuedPredecessors為true怖辆,compareAndSetState為false祷肯,調(diào)用addWaiter,進(jìn)入acquireQueued,
             判斷p == head ==true,并且再次tryAcquire進(jìn)行compareAndSetState失敗疗隶,然后被park佑笋,最后第一個(gè)線程釋放狀態(tài),也會(huì)調(diào)用unparkSuccessor斑鼻,但是當(dāng)前head節(jié)點(diǎn)是一個(gè)空節(jié)點(diǎn)并沒有Thread在其中蒋纬。即使是這樣
             unparkSuccessor喚醒的是head的next節(jié)點(diǎn),而釋放鎖的線程不是head坚弱,thread為null的線程才是當(dāng)前head蜀备,所以第二個(gè)線程依然可以被喚醒并成為head。這里說明了當(dāng)前執(zhí)行的線程不總是head線程荒叶,
             喚醒下一個(gè)節(jié)點(diǎn)的線程也不總是head節(jié)點(diǎn)的線程碾阁。當(dāng)前釋放鎖的線程可能不是head節(jié)點(diǎn),也沒有進(jìn)入隊(duì)列中些楣。
           2脂凶、h不為空,h的waitStatus =0 意味著沒有后續(xù)節(jié)點(diǎn)需要被喚醒否則waitStatus=Node.SINGAL,表示有繼任節(jié)點(diǎn)愁茁,當(dāng)前的節(jié)點(diǎn)的waitStatus=Node.SINGAL只能由后續(xù)節(jié)點(diǎn)設(shè)置
           **/
           if (h != null && h.waitStatus != 0) 
               unparkSuccessor(h);
           return true;
       }
       //false 表示釋放鎖失敗蚕钦,可能當(dāng)前釋放鎖的線程和獲取鎖的線程不是同一個(gè),當(dāng)然tryRelease 可選拋出還是不拋出異常鹅很。這里返回false只是穩(wěn)妥的方式嘶居。
       //以便其他方法在調(diào)用時(shí)可以使用這個(gè)判斷標(biāo)志作為依賴而拋出其他異常或者設(shè)置新的標(biāo)志,例如后面講到fullRelease的時(shí)候會(huì)說到
       return false;
   }
    //ReentrantLock#Sync#tryRelease
     protected final boolean tryRelease(int releases) {
            //state是共享變量為什么這里不用加鎖呢促煮?很簡(jiǎn)單只有獲取到鎖的線程才能釋放邮屁,這里其實(shí)只當(dāng)前鎖線程才能釋放
            int c = getState() - releases;
            //持有鎖的線程是當(dāng)前線程,否則拋出異常菠齿。
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
     /**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
         //嘗試在unpark前清除node當(dāng)前的等待狀態(tài)(由Node.SIGNAL 變?yōu)?)佑吝,失敗和被等待線程修改都沒有關(guān)系,這個(gè)操作不重要泞当。
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        //下一個(gè)節(jié)點(diǎn)為null或者被取消則迹蛤,從tail節(jié)點(diǎn)向前民珍,進(jìn)行掃描直到找到waitStatus<=0 (最后一個(gè)襟士,離head最近的那一個(gè))即需要被喚醒盗飒,
        //同時(shí)將找到的節(jié)點(diǎn)賦值給node.next 實(shí)際上對(duì)其中狀態(tài)>0被取消的節(jié)點(diǎn)進(jìn)行了裁剪,但是只設(shè)置了node的next屬性并未設(shè)置prev屬性陋桂。
        //只有一個(gè)地方是用來徹底釋放取消節(jié)點(diǎn)的逆趣。即在shouldParkAfterFailedAcquire中。
        //這里首先進(jìn)行next屬性的嘗試嗜历,但是因?yàn)閚ext節(jié)點(diǎn)不總是可靠宣渗,有可能節(jié)點(diǎn)被取消或者next屬性值還沒被賦值。所以使用next屬性實(shí)際上是一種優(yōu)化
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        //找到next節(jié)點(diǎn)后喚醒他
        if (s != null)
            LockSupport.unpark(s.thread);
    }

好了公平鎖完完整的流程就走完了梨州。下面繼續(xù)分析ReentrantLock其他的方法痕囱。

        獲取鎖除非當(dāng)前線程被中斷
        如果當(dāng)前鎖沒有被其他線程持有,則立即返回并且設(shè)置hold count 為1
        如果當(dāng)前線程持有這個(gè)鎖暴匠,hold count加1 并且立即返回
        如果當(dāng)前鎖被其他線程持有鞍恢,當(dāng)前線程將變得不會(huì)被線程調(diào)度,假死直到下面兩種情況之一發(fā)生:
         1.當(dāng)前線程主動(dòng)獲取鎖(被前驅(qū)節(jié)點(diǎn)喚醒)
         2.其他線程調(diào)用 Thread.interrupt 中斷這個(gè)線程(在線程獲取鎖的時(shí)候被中斷)
         主動(dòng)獲取鎖成功和lock方法效果是一樣的每窖,如果線程在等待的過程中被中斷將拋出 InterruptedException帮掉,并且當(dāng)前線程的中斷狀態(tài)被重新設(shè)置
        此方法具有優(yōu)先檢測(cè)中斷的能力
      **/
      //#ReentrantLock#lockInterruptibly
      public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
     /**
       獨(dú)占式的獲取鎖,中斷的時(shí)候終止窒典。
       通過首先檢查中斷狀態(tài)蟆炊,然后調(diào)用至少一次的tryAquire,在成功的時(shí)候返回瀑志。否則這個(gè)線程被入隊(duì)涩搓,可能重復(fù)的阻塞或者解阻塞,(第一次進(jìn)來無法獲取鎖劈猪,阻塞缩膝。后面有可能其他節(jié)點(diǎn)線程獲取鎖發(fā)生異常,cancelAquire會(huì)調(diào)用unparkSuccessor岸霹,
        當(dāng)前節(jié)點(diǎn)有可能被喚醒疾层,判斷head不是自己前驅(qū),進(jìn)行取消節(jié)點(diǎn)裁剪后贡避,則再次阻塞痛黎,直到head是自己的前驅(qū)并且調(diào)用release方法重置狀態(tài),喚醒自己刮吧,線程再次被喚醒)
       然后調(diào)用tryAcquire湖饱, 直到成功獲取到鎖或者這個(gè)線程被中斷。
     **/
     
     public final void acquireInterruptibly(int arg)
            throws InterruptedException {
            //首先判斷中斷狀態(tài)
        if (Thread.interrupted())
            throw new InterruptedException();
            //tryAquire不再分析杀捻,公平鎖和非公平鎖的區(qū)別在于是調(diào)用hasQueuedPredecessors井厌,此處是公平鎖
            //tryAquire 判斷隊(duì)列是否有節(jié)點(diǎn),CAS設(shè)置狀態(tài)等不再前面已經(jīng)說過。
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }
       
/**
         獨(dú)占獲取并且響應(yīng)中斷
         和acquireQueued 對(duì)比
         acquireQueued 有返回值 參數(shù)為Node 忽略中斷 入隊(duì)操作在外層aquire中(方便被重用)
         doAcquireInterruptibly 無返回值 參數(shù)為aquire的數(shù)量 顯示拋出InterruptedException 入隊(duì)操作在自己方法體中
       **/
        private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    //注意:被喚醒之后如果檢測(cè)中斷狀態(tài)被設(shè)置仅仆,才接著拋出異常
                    throw new InterruptedException();
            }
        } finally {
            if (failed) //拋出InterruptedException 后 failed=true器赞,執(zhí)行取消流程。
                cancelAcquire(node);
        }
    }
**總結(jié):doAcquireInterruptibly嘗試獲取鎖時(shí)會(huì)檢測(cè)中斷狀態(tài)墓拜,拋出異常港柜。
    在unpark之后會(huì)檢測(cè)中斷狀態(tài)拋出異常。這都是在獲取鎖的過程中最大努力的處理中斷咳榜,
    但還是有延遲夏醉,線程被park住了,即使有中斷也無法拋出涌韩。acquireQueued也可以完全設(shè)置的和doAcquireInterruptibly參數(shù)
    返回值都一樣畔柔,acquireQueued只是為了方便重用。同樣都用try finally 取消線程(或者說設(shè)置線程的取消狀態(tài))臣樱。其他流程都和acquireQueued一樣靶擦。**
/**
    請(qǐng)求這個(gè)鎖并立即返回。如果當(dāng)前鎖未被其他線程持有返回true擎淤,否則false奢啥。
    注意:即使構(gòu)造ReentrantLock時(shí)設(shè)置公平狀態(tài)為公平鎖,tryLcok仍然是調(diào)用的非公平的嘴拢。
        這個(gè)行為在某些情況下非常用于桩盲,即使你使用了公平鎖,仍然可以不判斷隊(duì)列狀態(tài)席吴,嘗試獲取鎖赌结,只要當(dāng)前鎖CAS嘗試修改狀態(tài)成功。
**/
//#ReentrantLock#tryLock
 public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
/**
  獲取鎖如果在給定的等待時(shí)間內(nèi)孝冒,并且當(dāng)前線程沒有被中斷
  如果ReentrantLock已經(jīng)被設(shè)置為公平模式柬姚,那么這個(gè)方法必須遵守排隊(duì)策略。這個(gè)是和tryLock方法相反的庄涡。
  可以像下面這樣使用組合非公平和公平鎖同時(shí)利用兩種鎖的優(yōu)點(diǎn):
  if(lock.tryLock() || lock.tryLock(timeout,unit)){
  }
  和不帶參數(shù)的tryLock比較:
  tryLock(): 非公平鎖 立即返回 可檢測(cè)中斷 
  tryLock(timeout,unit):公平 (超時(shí))等待阻塞 可檢測(cè)中斷
**/
 //#ReentrantLock#tryLock(long timeout, TimeUnit unit)
  public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
  /**
   排他模式下使用量承,可響應(yīng)中斷,超時(shí)失敗返回false穴店。
   也是首先檢查中斷狀態(tài)撕捍,然后調(diào)用至少一次的tryAquire,成功就直接返回泣洞。否則
   將排隊(duì)等待忧风,可能重復(fù)的park或者unpark。知道最后調(diào)用tryAquire成功球凰,或者中斷狮腿、超時(shí)腿宰。
   第一個(gè)參數(shù)值是 :aquire的數(shù)量 第二個(gè)參數(shù)值是:等待的納秒
   返回true:tryAquire成功,false:超時(shí)
  **/
 //#AQS#tryAcquireNanos
 public final boolean tryAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
        //首先檢測(cè)中斷狀態(tài)
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquire(arg) ||
        doAcquireNanos(arg, nanosTimeout);
}
 /**
  排他模式下超時(shí)方法使用
  
 **/
 //#AQS#doAcquireNanos
private boolean doAcquireNanos(int arg, long nanosTimeout)
        throws InterruptedException {
    if (nanosTimeout <= 0L)//時(shí)間<=0 直接返回false缘厢,即失敗
        return false;
    final long deadline = System.nanoTime() + nanosTimeout;//等待截止時(shí)間
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return true;
            }
            nanosTimeout = deadline - System.nanoTime();
            if (nanosTimeout <= 0L) //等待時(shí)間到了直接返回false
                return false;
            //可以這么理解截止時(shí)間減去第一次嘗試tryAquire的時(shí)間=剩下的時(shí)間<自旋閥值的話將一直自旋吃度,否則剩下的時(shí)間將park住。
            //然后自己醒來昧绣,再判斷中斷狀態(tài)规肴,再進(jìn)行嘗試獲取鎖捶闸,最后重新判斷剩余時(shí)間<=0 返回false.
            //返回false之后因?yàn)閒ailed=true夜畴,執(zhí)行cancelAcquire,取消節(jié)點(diǎn)删壮。
            if (shouldParkAfterFailedAcquire(p, node) && 
                nanosTimeout > spinForTimeoutThreshold)
                LockSupport.parkNanos(this, nanosTimeout);
            if (Thread.interrupted())
                throw new InterruptedException();
        }
    } finally {
        if (failed) //這里的cancelAquire需要處理兩種情況的異常: 1.返回false贪绘,即超時(shí),可認(rèn)為超時(shí)也是一種異常央碟。2.中斷 cancelAquire流程見前面分析:cancelAcquire
            cancelAcquire(node);
    }
}
######總結(jié):doAcquireNanos 通過spinForTimeoutThreshold税灌,自己進(jìn)入等待,防止傳入等待時(shí)間過長(zhǎng)亿虽,自旋時(shí)間太長(zhǎng)菱涤,過多浪費(fèi)CPU資源,限制了最長(zhǎng)自旋時(shí)間不超過1000納秒洛勉。LockSupport.parkNanos(this, nanosTimeout);則讓線程在隨后的時(shí)間睡眠粘秆,直到給定的時(shí)間,自動(dòng)喚醒自己收毫。當(dāng)然也可以被頭節(jié)點(diǎn)喚醒攻走。無論被誰喚醒線程被unblock后.首先檢查下中斷狀態(tài),然后判斷下是否是head節(jié)點(diǎn)此再,截止獲取下鎖昔搂。如果不成功則,就超時(shí)输拇。所以即便線程超時(shí)他還是有最后一次機(jī)會(huì)去證明自己摘符。
 /**
    查詢是否有任何線程在排隊(duì)等待獲取鎖。
    注意:因?yàn)槿∠赡馨l(fā)生在任何時(shí)候策吠,返回true并不保證任何其他線程將一定獲取到這個(gè)鎖逛裤。
        這個(gè)方法主要被設(shè)計(jì)用來監(jiān)控系統(tǒng)的狀態(tài)。
 **/
//#ReentrantLock#hasQueuedThreads
 public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}
/**
    只是判斷頭結(jié)點(diǎn)不等于尾節(jié)點(diǎn)奴曙。
**/
 //#AQS#hasQueuedThreads
  public final boolean hasQueuedThreads() {
    return head != tail;
}
/**
     給定一個(gè)線程判斷他是否在隊(duì)列中等待獲取鎖别凹。
     注意:取消可能發(fā)生在任何時(shí)候,返回true洽糟,不保證這個(gè)線程將一定獲取到這個(gè)鎖炉菲。
            這個(gè)方法主要被設(shè)計(jì)用來監(jiān)控系統(tǒng)的狀態(tài)堕战。
**/

//#ReentrantLock#hasQueuedThread
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}

/**
從后向前遍歷找到這個(gè)線程,找到返回true拍霜,未找到返回false嘱丢。
**/
//AQS#isQueued
public final boolean isQueued(Thread thread) {
if (thread == null)
throw new NullPointerException();
for (Node p = tail; p != null; p = p.prev)
if (p.thread == thread)
return true;
return false;
}

#### AQS和ReentrantLock  (公平鎖和非公平鎖部分)的總結(jié):
AQS做的事情是管理隊(duì)列,然后提供一些監(jiān)控方法祠饺,子類只需要實(shí)現(xiàn) protected 標(biāo)記未exclusive的方法,其中有關(guān)獨(dú)占模式的AQS中最重要的管理隊(duì)列的方法: 
- 實(shí)現(xiàn)AQS核心算法排隊(duì)自旋有關(guān):
    acquireQueued:提供最基本的鎖獲取方式越驻。
    doAcquireInterruptibly:在acquireQueued中增加可響應(yīng)中斷
    doAcquireNanos:在doAcquireInterruptibly的基礎(chǔ)上增加可設(shè)置超時(shí)
    acquire**類方法一般形如如下模板:
    try{
      for(;;;){
        //判斷是否頭節(jié)點(diǎn)&&tryAcquire成功{設(shè)置頭節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn),前頭節(jié)點(diǎn)出隊(duì)道偷,最后返回成功}
        //判斷是否需要park
        //park
        //超時(shí)處理
        //中斷處理
      }
    }finally{
        if(failed)
            cannelAcquire;
    }
    shouldParkAfterFailedAcquire:節(jié)點(diǎn)狀態(tài)是實(shí)現(xiàn)前驅(qū)節(jié)點(diǎn)喚醒后驅(qū)節(jié)點(diǎn)設(shè)置狀態(tài)為Node.SIGNAL的唯一地方其他方法中也可以設(shè)置如cancelAcquire缀旁,但是不保證成功。
    unparkSuccessor:根據(jù)shouldParkAfterFailedAcquire設(shè)置的waitStatus來喚醒后驅(qū)節(jié)點(diǎn)
    release:釋放鎖(修改狀態(tài))勺鸦,可能調(diào)用unparkSuccessor并巍。
- 管理隊(duì)列性能、優(yōu)化相關(guān):
    cancelAcquire:取消無效節(jié)點(diǎn)换途,設(shè)置狀態(tài)為Node.CANCELLED
    shouldParkAfterFailedAcquire:也會(huì)清除被取消的節(jié)點(diǎn)
    unparkSuccessor:也會(huì)清除被取消的節(jié)點(diǎn)
-原始隊(duì)列原子操作相關(guān):
    enq懊渡、addWaiter
- 監(jiān)控相關(guān):
    hasQueuedThreads、hasQueuedThread
    子類只需要實(shí)現(xiàn):
    tryAcquire():通過setState军拟、getState設(shè)置修改狀態(tài)
    release():子類可能不叫releas叫 unlock剃执,同樣也是設(shè)置狀態(tài),
- 公平非公平鎖實(shí)現(xiàn)相關(guān):
    hasQueuedPredecessors:獲取隊(duì)列中是否有比自己排隊(duì)更久的節(jié)點(diǎn)懈息。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肾档,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子漓拾,更是在濱河造成了極大的恐慌阁最,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骇两,死亡現(xiàn)場(chǎng)離奇詭異速种,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)低千,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門配阵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人示血,你說我怎么就攤上這事棋傍。” “怎么了难审?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵瘫拣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我告喊,道長(zhǎng)麸拄,這世上最難降的妖魔是什么派昧? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮拢切,結(jié)果婚禮上蒂萎,老公的妹妹穿的比我還像新娘。我一直安慰自己淮椰,他們只是感情好五慈,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著主穗,像睡著了一般泻拦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上黔牵,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天聪轿,我揣著相機(jī)與錄音爷肝,去河邊找鬼猾浦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛灯抛,可吹牛的內(nèi)容都是我干的金赦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼对嚼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼夹抗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纵竖,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤漠烧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后靡砌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體已脓,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年通殃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了度液。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡画舌,死狀恐怖堕担,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曲聂,我是刑警寧澤霹购,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站朋腋,受9級(jí)特大地震影響齐疙,放射性物質(zhì)發(fā)生泄漏兢仰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一剂碴、第九天 我趴在偏房一處隱蔽的房頂上張望把将。 院中可真熱鬧,春花似錦忆矛、人聲如沸察蹲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洽议。三九已至,卻和暖如春漫拭,著一層夾襖步出監(jiān)牢的瞬間亚兄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工采驻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留审胚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓礼旅,卻偏偏與公主長(zhǎng)得像膳叨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痘系,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容