AQS源碼分析

一、作用

簡(jiǎn)單說(shuō):AQS就是在多線程搶奪共享資源的時(shí)候,實(shí)現(xiàn)了統(tǒng)一規(guī)劃資源步悠,確保只有一個(gè)線程搶奪成功,其他的都排隊(duì)的框架

AQS核心思想:如果被請(qǐng)求的共享資源空閑瘫镇,那么當(dāng)前線程設(shè)置為獨(dú)占線程鼎兽,將當(dāng)前資源設(shè)定為鎖定狀態(tài),如果有其他線程也要訪問(wèn)這個(gè)被鎖定的共享資源铣除,那么就需要一套線程阻塞及被喚醒的分配機(jī)制谚咬,aqs是通過(guò)CLH隊(duì)列鎖實(shí)現(xiàn)的,將獲取不到鎖的線程加到隊(duì)列中通孽。

CLH是啥:FIFO雙向隊(duì)列, 如下圖(圖片來(lái)自網(wǎng)絡(luò)):

img

AQS的CLH實(shí)現(xiàn):

static final class Node {
        /** 標(biāo)識(shí)節(jié)點(diǎn)在共享模式下等待*/
        static final Node SHARED = new Node();
        /** 標(biāo)識(shí)節(jié)點(diǎn)在獨(dú)占模式下等待*/
        static final Node EXCLUSIVE = null;

        /** waitStatus 當(dāng)前線程被取消 */
        static final int CANCELLED =  1;
        /** waitStatus 當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)包含的線程需要運(yùn)行序宦,也就是unpark */
        static final int SIGNAL    = -1;
        /** waitStatus 表示當(dāng)前節(jié)點(diǎn)在等待condition,也就是在condition隊(duì)列中 */
        static final int CONDITION = -2;
        /**
         * waitStatus 表示當(dāng)前場(chǎng)景下后續(xù)的acquireShared能夠得以執(zhí)行
         */
        static final int PROPAGATE = -3;

      
        volatile int waitStatus;

        /**
         * 節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
         */
        volatile Node prev;

        /**
         * 節(jié)點(diǎn)的后繼節(jié)點(diǎn)
         */
        volatile Node next;

        /**
         * 當(dāng)前的線程
         */
        volatile Thread thread;

        /**
         * 隊(duì)列中下一個(gè)等待的線程
         */
        Node nextWaiter;

        /**
         * 如果節(jié)點(diǎn)在共享模式下等待,則返回true互捌。
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * 返回當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

二潘明、waitStatus 結(jié)點(diǎn)狀態(tài)

  1. CANCELLED,值為1秕噪,表示當(dāng)前的線程被取消
  2. SIGNAL钳降,值為-1,表示當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)包含的線程需要運(yùn)行腌巾,也就是unpark
  3. CONDITION遂填,值為-2,表示當(dāng)前節(jié)點(diǎn)在等待condition澈蝙,也就是在condition隊(duì)列中
  4. PROPAGATE吓坚,值為-3,表示當(dāng)前場(chǎng)景下后續(xù)的acquireShared能夠得以執(zhí)行
  5. 值為0灯荧,表示當(dāng)前節(jié)點(diǎn)在sync隊(duì)列中礁击,等待著獲取鎖

三、核心acquire 說(shuō)明(此部分相當(dāng)于ReentrantLock.lock()的過(guò)程)

image.png

從ReentrantLock的lock開(kāi)始看吧
new ReentrantLock()默認(rèn)構(gòu)造是非公平鎖逗载,是否公平主要取決于是否按順序去爭(zhēng)搶共享資源椒惨。

public void lock() {
        sync.lock(); //加鎖開(kāi)始
    }

有兩種是實(shí)現(xiàn)一種是公平一種是非公平囚聚,這里是非公平

非公平鎖

/**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            //直接cas方式去搶鎖如果搶成功則設(shè)置當(dāng)前新線程為獨(dú)占線程憎茂。(1)
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

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

公平鎖乳规,區(qū)別就在于嘗試加鎖的時(shí)候,如上(1)非公平鎖在當(dāng)前資源沒(méi)有被任何線程搶占的時(shí)候能直接搶到資源擦秽,公平鎖則會(huì)進(jìn)行hasQueuedPredecessors判斷,也就是嚴(yán)格按照加入隊(duì)列的順序码荔,F(xiàn)IFO。

非公平鎖的性能高于公平鎖的原因:在恢復(fù)一個(gè)被掛起的線程與該線程真正運(yùn)行之間存在著嚴(yán)重的延遲感挥。

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        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) {
            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;
    }
}

//判斷head和tail不相等(說(shuō)明有等待線程)并且(head.next為null=>說(shuō)明有線程正在入隊(duì)列的中間狀態(tài)目胡,肯定不是當(dāng)前線程, 因?yàn)橐粋€(gè)線程一個(gè)時(shí)間只能做一件事 或者 head.next.thread不是當(dāng)前線程),主要是防止中間狀態(tài)的時(shí)候?qū)е虏还降囊蛩爻霈F(xiàn)链快,那么我理解非公平的吞吐量肯定更好好于公平的。
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;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

第一次CAS失敗進(jìn)入這里

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&  //如果tryAcquire失敗了眉尸,那就該進(jìn)入CLH隊(duì)列中排隊(duì)了域蜗。
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState(); //獲取當(dāng)前狀態(tài)
            if (c == 0) {//代表未被占用
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);//設(shè)置為獨(dú)占
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //如果當(dāng)前線程是當(dāng)前獨(dú)占資源的線程
                int nextc = c + acquires; //代表重入
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc); //這里說(shuō)明當(dāng)前線程重入幾次就加幾
                return true;
            }
            return false;
        }

tryAcquire 執(zhí)行失敗,則進(jìn)入排隊(duì)

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode); //構(gòu)造一個(gè)新的節(jié)點(diǎn)
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail; 
        if (pred != null) {
            node.prev = pred;//當(dāng)前隊(duì)列尾節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)的頭結(jié)點(diǎn)
            if (compareAndSetTail(pred, node)) {//cas 方式設(shè)置當(dāng)前節(jié)點(diǎn)作為隊(duì)列尾節(jié)點(diǎn)
                pred.next = node; //設(shè)置之前的尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)噪猾。
                return node;
            }
        }
        enq(node);//當(dāng)前隊(duì)列不存在霉祸,需要初始化。
        return node;
    }

隊(duì)列初始化過(guò)程

 private Node enq(final Node node) {
        for (;;) { //這里多說(shuō)一句 for這種用法和while(true)一致
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))// 各種cas操作
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {//如果有一個(gè)節(jié)點(diǎn)袱蜡,直接把當(dāng)前節(jié)點(diǎn)作為尾節(jié)點(diǎn)
                    t.next = node;
                    return t;
                }
            }
        }
    }

tryAcquire() 和 addWaiter()獲取資源失敗丝蹭,放入隊(duì)列尾部,則進(jìn)行下一步:

自旋一直try

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;  //標(biāo)識(shí)位 默認(rèn)是true是代表拿到了資源
        try {
            boolean interrupted = false; //代表是否被中斷過(guò)坪蚁,這個(gè)在parkAndCheckInterrupt里面說(shuō)比較合適
            for (;;) {//又自旋
                final Node p = node.predecessor();//前驅(qū)節(jié)點(diǎn)
              //只有前驅(qū)是頭結(jié)點(diǎn)了奔穿,他才能參與搶資源镜沽,不是老二就都沒(méi)有資格而且只有當(dāng)前頭結(jié)點(diǎn)釋放資源了或者被中斷了他才能搶到。贱田。
                if (p == head && tryAcquire(arg)) {//自旋一直去嘗試獲取資源
                    setHead(node);//獲取到了則將
                    p.next = null; // help GC 方便GC這個(gè)不用說(shuō)了
                    failed = false;
                    return interrupted;
                }
              //進(jìn)入waiting狀態(tài)缅茉,直到被中斷或者被調(diào)用unpark,詳情看下面的分析
                if (shouldParkAfterFailedAcquire(p, node) && //
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

Node.SIGNAL:waitStatus值男摧,指示后續(xù)線程需要取消waiting(也就是unpark或者中斷)

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus; //前驅(qū)節(jié)點(diǎn)的狀態(tài)
        if (ws == Node.SIGNAL) //是前驅(qū)節(jié)點(diǎn)就返回true
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {//說(shuō)明前驅(qū)節(jié)點(diǎn)已經(jīng)被取消了蔬墩,
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev; //然后就跳過(guò)當(dāng)前無(wú)效節(jié)點(diǎn)去找有效的。
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * 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);//如果有效設(shè)置前驅(qū)節(jié)點(diǎn)的狀態(tài)為SIGNAL
        }
        return false;
    }

設(shè)置當(dāng)前線程為等待狀態(tài)且看線程是否被中斷過(guò)耗拓,并清除中斷標(biāo)識(shí)拇颅。

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

總結(jié):

  1. 調(diào)用tryAcquire() 嘗試直接去獲取資源,如果成功則直接返回乔询;
  2. 沒(méi)成功樟插,則addWaiter() 將該線程加入等待隊(duì)列的尾部,并標(biāo)記為獨(dú)占模式哥谷;
  3. acquireQueued()讓線程在等待隊(duì)列中處于waiting狀態(tài)岸夯,當(dāng)輪到當(dāng)前線程,也就是當(dāng)前成為頭結(jié)點(diǎn)的后繼節(jié)點(diǎn)们妥,則會(huì)被unpark())會(huì)去嘗試獲取資源猜扮。獲取到資源后才返回。如果在整個(gè)等待過(guò)程中被中斷過(guò)监婶,則返回true旅赢,否則返回false。
  4. 如果線程在等待過(guò)程中被中斷過(guò)惑惶,哪怕一次煮盼,也是不會(huì)干活的,會(huì)在搶到資源后進(jìn)行selfInterrupt()自己中斷自己带污,有點(diǎn)后置僵控。

四、核心release說(shuō)明(此部分相當(dāng)于ReentrantLock.unlock()的過(guò)程)

release相當(dāng)于acquire的相反操作鱼冀,也就是釋放資源报破,釋放指定量的資源。

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

tryRelease是ReentrantLock中的實(shí)現(xiàn)

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();//也就是當(dāng)前的線程不是此對(duì)象監(jiān)視器的所有者千绪。也就是要在當(dāng)前線程鎖定對(duì)象充易,才能用鎖定的對(duì)象此行這些方法.
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

喚醒等待隊(duì)列中下一個(gè)線程

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.
     */
    int ws = node.waitStatus;
    if (ws < 0)//如果狀態(tài)為負(fù)(即可能需要信號(hào)),則嘗試在預(yù)期信號(hào)時(shí)清除荸型。如果失敗或者狀態(tài)被等待線程更改盹靴,這是正常的。
        compareAndSetWaitStatus(node, ws, 0);//head節(jié)點(diǎn)狀態(tài)設(shè)置成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.
     */
  //unpark的線程保存在后續(xù)節(jié)點(diǎn)中,后者通常只是下一個(gè)節(jié)點(diǎn)稿静。但如果被取消或明顯為空梭冠,則從尾部向后移動(dòng)以找到實(shí)際的未取消的繼承者。
    Node s = node.next;
    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;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

總結(jié):

只有(state=0)才會(huì)將資源徹底釋放自赔。

參考資料

線程狀態(tài)說(shuō)明 1

線程狀態(tài)說(shuō)明 2

image.png

從ReentrantLock的lock開(kāi)始看吧

new ReentrantLock()默認(rèn)構(gòu)造是非公平鎖妈嘹,是否公平主要取決于是否按順序去爭(zhēng)搶共享資源。

public void lock() {
        sync.lock(); //加鎖開(kāi)始
    }

有兩種是實(shí)現(xiàn)一種是公平一種是非公平绍妨,這里是非公平

image.png

非公平鎖

/**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            //直接cas方式去搶鎖如果搶成功則設(shè)置當(dāng)前新線程為獨(dú)占線程润脸。(1)
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

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

公平鎖,區(qū)別就在于嘗試加鎖的時(shí)候他去,如上(1)非公平鎖在當(dāng)前資源沒(méi)有被任何線程搶占的時(shí)候能直接搶到資源毙驯,公平鎖則會(huì)進(jìn)行hasQueuedPredecessors判斷,也就是嚴(yán)格按照加入隊(duì)列的順序,F(xiàn)IFO灾测。

非公平鎖的性能高于公平鎖的原因:在恢復(fù)一個(gè)被掛起的線程與該線程真正運(yùn)行之間存在著嚴(yán)重的延遲爆价。

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        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) {
            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;
    }
}

//判斷head和tail不相等(說(shuō)明有等待線程)并且(head.next為null=>說(shuō)明有線程正在入隊(duì)列的中間狀態(tài),肯定不是當(dāng)前線程, 因?yàn)橐粋€(gè)線程一個(gè)時(shí)間只能做一件事 或者 head.next.thread不是當(dāng)前線程)媳搪,主要是防止中間狀態(tài)的時(shí)候?qū)е虏还降囊蛩爻霈F(xiàn)铭段,那么我理解非公平的吞吐量肯定更好好于公平的。
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;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

第一次CAS失敗進(jìn)入這里

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&  //如果tryAcquire失敗了秦爆,那就該進(jìn)入CLH隊(duì)列中排隊(duì)了序愚。
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState(); //獲取當(dāng)前狀態(tài)
            if (c == 0) {//代表未被占用
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);//設(shè)置為獨(dú)占
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) { //如果當(dāng)前線程是當(dāng)前獨(dú)占資源的線程
                int nextc = c + acquires; //代表重入
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc); //這里說(shuō)明當(dāng)前線程重入幾次就加幾
                return true;
            }
            return false;
        }

tryAcquire 執(zhí)行失敗,則進(jìn)入排隊(duì)

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode); //構(gòu)造一個(gè)新的節(jié)點(diǎn)
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail; 
        if (pred != null) {
            node.prev = pred;//當(dāng)前隊(duì)列尾節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)的頭結(jié)點(diǎn)
            if (compareAndSetTail(pred, node)) {//cas 方式設(shè)置當(dāng)前節(jié)點(diǎn)作為隊(duì)列尾節(jié)點(diǎn)
                pred.next = node; //設(shè)置之前的尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)等限。
                return node;
            }
        }
        enq(node);//當(dāng)前隊(duì)列不存在爸吮,需要初始化。
        return node;
    }

隊(duì)列初始化過(guò)程

 private Node enq(final Node node) {
        for (;;) { //這里多說(shuō)一句 for這種用法和while(true)一致
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))// 各種cas操作
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {//如果有一個(gè)節(jié)點(diǎn)望门,直接把當(dāng)前節(jié)點(diǎn)作為尾節(jié)點(diǎn)
                    t.next = node;
                    return t;
                }
            }
        }
    }

tryAcquire() 和 addWaiter()獲取資源失敗形娇,放入隊(duì)列尾部,則進(jìn)行下一步:

自旋一直try

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;  //標(biāo)識(shí)位 默認(rèn)是true是代表拿到了資源
        try {
            boolean interrupted = false; //代表是否被中斷過(guò)筹误,這個(gè)在parkAndCheckInterrupt里面說(shuō)比較合適
            for (;;) {//又自旋
                final Node p = node.predecessor();//前驅(qū)節(jié)點(diǎn)
              //只有前驅(qū)是頭結(jié)點(diǎn)了桐早,他才能參與搶資源,不是老二就都沒(méi)有資格而且只有當(dāng)前頭結(jié)點(diǎn)釋放資源了或者被中斷了他才能搶到厨剪。勘畔。
                if (p == head && tryAcquire(arg)) {//自旋一直去嘗試獲取資源
                    setHead(node);//獲取到了則將
                    p.next = null; // help GC 方便GC這個(gè)不用說(shuō)了
                    failed = false;
                    return interrupted;
                }
              //進(jìn)入waiting狀態(tài),直到被中斷或者被調(diào)用unpark丽惶,詳情看下面的分析
                if (shouldParkAfterFailedAcquire(p, node) && //
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

Node.SIGNAL:waitStatus值,指示后續(xù)線程需要取消waiting(也就是unpark或者中斷)

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus; //前驅(qū)節(jié)點(diǎn)的狀態(tài)
        if (ws == Node.SIGNAL) //是前驅(qū)節(jié)點(diǎn)就返回true
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {//說(shuō)明前驅(qū)節(jié)點(diǎn)已經(jīng)被取消了爬立,
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev; //然后就跳過(guò)當(dāng)前無(wú)效節(jié)點(diǎn)去找有效的钾唬。
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * 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);//如果有效設(shè)置前驅(qū)節(jié)點(diǎn)的狀態(tài)為SIGNAL
        }
        return false;
    }

設(shè)置當(dāng)前線程為等待狀態(tài)且看線程是否被中斷過(guò),并清除中斷標(biāo)識(shí)。

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

總結(jié):

  1. 調(diào)用tryAcquire() 嘗試直接去獲取資源抡秆,如果成功則直接返回奕巍;
  2. 沒(méi)成功,則addWaiter() 將該線程加入等待隊(duì)列的尾部儒士,并標(biāo)記為獨(dú)占模式的止;
  3. acquireQueued()讓線程在等待隊(duì)列中處于waiting狀態(tài),當(dāng)輪到當(dāng)前線程着撩,也就是當(dāng)前成為頭結(jié)點(diǎn)的后繼節(jié)點(diǎn)诅福,則會(huì)被unpark())會(huì)去嘗試獲取資源。獲取到資源后才返回拖叙。如果在整個(gè)等待過(guò)程中被中斷過(guò)氓润,則返回true,否則返回false薯鳍。
  4. 如果線程在等待過(guò)程中被中斷過(guò)咖气,哪怕一次,也是不會(huì)干活的挖滤,會(huì)在搶到資源后進(jìn)行selfInterrupt()自己中斷自己崩溪,有點(diǎn)后置。

四斩松、核心release說(shuō)明(此部分相當(dāng)于ReentrantLock.unlock()的過(guò)程)

release相當(dāng)于acquire的相反操作伶唯,也就是釋放資源,釋放指定量的資源砸民。

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

tryRelease是ReentrantLock中的實(shí)現(xiàn)

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();//也就是當(dāng)前的線程不是此對(duì)象監(jiān)視器的所有者抵怎。也就是要在當(dāng)前線程鎖定對(duì)象,才能用鎖定的對(duì)象此行這些方法.
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

喚醒等待隊(duì)列中下一個(gè)線程

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.
     */
    int ws = node.waitStatus;
    if (ws < 0)//如果狀態(tài)為負(fù)(即可能需要信號(hào))岭参,則嘗試在預(yù)期信號(hào)時(shí)清除反惕。如果失敗或者狀態(tài)被等待線程更改,這是正常的演侯。
        compareAndSetWaitStatus(node, ws, 0);//head節(jié)點(diǎn)狀態(tài)設(shè)置成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.
     */
  //unpark的線程保存在后續(xù)節(jié)點(diǎn)中姿染,后者通常只是下一個(gè)節(jié)點(diǎn)。但如果被取消或明顯為空秒际,則從尾部向后移動(dòng)以找到實(shí)際的未取消的繼承者悬赏。
    Node s = node.next;
    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;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

總結(jié):

只有(state=0)才會(huì)將資源徹底釋放。

參考資料

線程狀態(tài)說(shuō)明 1

線程狀態(tài)說(shuō)明 2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娄徊,一起剝皮案震驚了整個(gè)濱河市闽颇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寄锐,老刑警劉巖兵多,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尖啡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡剩膘,警方通過(guò)查閱死者的電腦和手機(jī)衅斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怠褐,“玉大人畏梆,你說(shuō)我怎么就攤上這事∧卫粒” “怎么了奠涌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)筐赔。 經(jīng)常有香客問(wèn)我铣猩,道長(zhǎng),這世上最難降的妖魔是什么茴丰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任达皿,我火速辦了婚禮,結(jié)果婚禮上贿肩,老公的妹妹穿的比我還像新娘峦椰。我一直安慰自己,他們只是感情好汰规,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布汤功。 她就那樣靜靜地躺著,像睡著了一般溜哮。 火紅的嫁衣襯著肌膚如雪滔金。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天茂嗓,我揣著相機(jī)與錄音餐茵,去河邊找鬼。 笑死述吸,一個(gè)胖子當(dāng)著我的面吹牛忿族,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝌矛,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼道批,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了入撒?” 一聲冷哼從身側(cè)響起隆豹,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茅逮,沒(méi)想到半個(gè)月后噪伊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體簿煌,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年鉴吹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惩琉。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡豆励,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞒渠,到底是詐尸還是另有隱情良蒸,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布伍玖,位于F島的核電站嫩痰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏窍箍。R本人自食惡果不足惜串纺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椰棘。 院中可真熱鬧纺棺,春花似錦、人聲如沸邪狞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)帆卓。三九已至巨朦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剑令,已是汗流浹背糊啡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尚洽,地道東北人悔橄。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像腺毫,于是被迫代替她去往敵國(guó)和親癣疟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349