溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解AQS源碼

發(fā)布時間:2021-10-19 16:42:17 來源:億速云 閱讀:122 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“如何理解AQS源碼”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

AQS abstractQueueSynchronizer(抽象隊(duì)列同步器),是什么?

答:它是用來構(gòu)建鎖 或者 其他同步器組件的重量級基礎(chǔ)框架,是整個JUC體系的基礎(chǔ)。通過內(nèi)置FIFO隊(duì)列來完成獲取線程取鎖的排隊(duì)工作,并通過一個int類型變量標(biāo)識持有鎖的狀態(tài);

    前置知識點(diǎn):

    1、可重入鎖(遞歸鎖):

    sync(隱式鎖,jvm管理)和ReentrantLock(Lock顯式鎖,就是手動加解)是重入鎖的典型代表,為可以重復(fù)使用的鎖。一個變成多個流程,可以獲取同一把鎖。

    可重入鎖概念: 是指一個線程,在外層方法獲取鎖的時候,再次進(jìn)入該線程的內(nèi)層方法會自動獲取鎖(必須是同一個對象),不會被阻塞??杀苊馑梨i

    舉例: 遞歸調(diào)用同一個 sync修飾的方法或者代碼塊。必須是一個對象才行。一個線程調(diào)用一個對象的method1,method1 調(diào)用method2,method2調(diào)用method3, 3個方法都是被sync修飾,這樣也是一個可重入鎖的例子 。

    再比如下面這種

static Object lock = new Object();
public void mm(){
    synchronized (lock){
        System.out.println("===========mm method");
        synchronized (lock){
            System.out.println("=========== method");
        }
    }
}

     只有一個對象 和同步代碼塊,如果sycn中嵌套sync 并都是lock對象,那么該線程就會持有當(dāng)前對象的鎖,并可重入。反編譯后發(fā)現(xiàn)

public void mm();
    Code:
       0: getstatic     #7                  // Field lock:Ljava/lang/Object;
       3: dup
       4: astore_1
       5: monitorenter
       6: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #9                  // String ===========mm method
      11: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: aload_1
      15: monitorexit
      16: goto          24
      19: astore_2
      20: aload_1
      21: monitorexit
      22: aload_2
      23: athrow
      24: return
    Exception table:
       from    to  target type
           6    16    19   any
          19    22    19   any

    sync同步代碼塊加解鎖,使用的命令為monitorenter 和 monitorexit(同步方法標(biāo)識是ACC_SYNCHRONIZED,在flag中),enter 為加鎖,必須成對出現(xiàn),但這里卻又兩個exit。原因?yàn)榈谝粋€exit為程序正常運(yùn)行后的解鎖命令,并執(zhí)行完后會執(zhí)行g(shù)oto到return ,也就是第24行,

    第二個exit 為當(dāng)程序出現(xiàn)異常時,需要執(zhí)行的解鎖命令;

如上就是可重入鎖的相關(guān)概念

    2、什么是LockSupport?

    根據(jù)jdk8 的api文檔顯示定義為: 用于創(chuàng)建鎖和其他同步類的基本線程阻塞原語; 

    是一個線程阻塞工具類,所有方法均為靜態(tài),可以讓線程在任意位置阻塞,阻塞后也有對應(yīng)的喚醒方法。

    先復(fù)習(xí)下object 對象的wait 和 notify 和Lock 的condition

  • wait 和notify 必須在sync 代碼塊中才能使用,否則報(bào)錯。非法的監(jiān)視器

  • condition的await 和 signal方法也必須在lock 和unlock方法前執(zhí)行,否則報(bào)錯,非法的監(jiān)視器

  • 線程一定要先 等待 ,再 被 喚醒,順序不能換

      LockSupport 有兩個關(guān)鍵函數(shù) park 和unpark,該類使用了Permit(許可證)的概念來阻塞和喚醒線程的功能。每個線程都會有一個Permit,該P(yáng)ermit 只有兩個值 0 和1 ,默認(rèn)是0。類似于信號量,但上限是1;

     來看park方法

public static void park() {
    //unsafe的方法。初始為0
    UNSAFE.park(false, 0L);
}

    禁止當(dāng)前線程進(jìn)行線程調(diào)度,除非Permit可用,就是1

    如果Permit 為1(有可用證書) 將變更為0(線程仍然會處理業(yè)務(wù)邏輯),并且立即返回。否則當(dāng)前線程對于線程調(diào)度目的將被禁用,并處于休眠狀態(tài)。直至發(fā)生三件事情之一:

  • 一些其他線程調(diào)用當(dāng)前線程作為目標(biāo)的unpark ; 要么

  • 其他一些線程當(dāng)前線程為interrupts ; 要么

  • 電話虛假(也就是說,沒有理由)返回。

     這種方法不報(bào)告是哪個線程導(dǎo)致該方法返回。 來電者應(yīng)重新檢查導(dǎo)致線程首先停放的條件。 呼叫者還可以確定線程在返回時的中斷狀態(tài)。

     小結(jié):Permit默認(rèn)0,所以一開始調(diào)用park,當(dāng)前線程被阻塞,直到別的線程將當(dāng)前線程的Permit修改為1,從park方法處被喚醒,處理業(yè)務(wù),然后會將permit修改為0,并返回;如果permit為1,調(diào)用park時會將permit修改為0,在執(zhí)行業(yè)務(wù)邏輯到線程生命周期。與park方法定義吻合。

     在看unpark方法:

public static void unpark(Thread thread) {
    if (thread != null)
        UNSAFE.unpark(thread);
}

     在調(diào)用unpark方法后,會將Thread線程的許可permit設(shè)置成1,會自動喚醒thread線程,即,之前阻塞中的LockSupport.park方法會立即返回,然后線程執(zhí)行業(yè)務(wù)邏輯 。 且 unpark可以在park之前執(zhí)行。相當(dāng)于執(zhí)行park沒有效果。

    3、AQS abstractQueueSynchronizer 源碼

    剩余前置知識為: 公平鎖、非公平鎖、自旋鎖、鏈表、模板設(shè)計(jì)模式

     AQS使用volatile修飾的int類型的變量 標(biāo)識鎖的狀態(tài),通過內(nèi)置的FIFO隊(duì)列來完成資源獲取的排隊(duì)工作,將每條要去搶占資源的線程封裝成node節(jié)點(diǎn)實(shí)現(xiàn)鎖的分配,通過CAS(自旋鎖)完成對state值的修改 ;

如何理解AQS源碼

    (1)node節(jié)點(diǎn)源碼

static final class Node {
        /** Marker to indicate a node is waiting in shared mode */
    	//共享節(jié)點(diǎn)
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
    	//獨(dú)占節(jié)點(diǎn)
        static final Node EXCLUSIVE = null;

        /** waitStatus value to indicate thread has cancelled */
    	//線程被取消狀態(tài)
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
    	//	后續(xù)線程需要喚醒
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
    	//鄧丹condition喚醒
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
    	//共享室同步狀態(tài)獲取 將會無條件傳播下去
        static final int PROPAGATE = -3;

        /**
         * Status field, taking on only the values:
         *   SIGNAL:     The successor of this node is (or will soon be)
         *               blocked (via park), so the current node must
         *               unpark its successor when it releases or
         *               cancels. To avoid races, acquire methods must
         *               first indicate they need a signal,
         *               then retry the atomic acquire, and then,
         *               on failure, block.
         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
         *               Nodes never leave this state. In particular,
         *               a thread with cancelled node never again blocks.
         *   CONDITION:  This node is currently on a condition queue.
         *               It will not be used as a sync queue node
         *               until transferred, at which time the status
         *               will be set to 0. (Use of this value here has
         *               nothing to do with the other uses of the
         *               field, but simplifies mechanics.)
         *   PROPAGATE:  A releaseShared should be propagated to other
         *               nodes. This is set (for head node only) in
         *               doReleaseShared to ensure propagation
         *               continues, even if other operations have
         *               since intervened.
         *   0:          None of the above
         *
         * The values are arranged numerically to simplify use.
         * Non-negative values mean that a node doesn't need to
         * signal. So, most code doesn't need to check for particular
         * values, just for sign.
         *
         * The field is initialized to 0 for normal sync nodes, and
         * CONDITION for condition nodes.  It is modified using CAS
         * (or when possible, unconditional volatile writes).
         */
    	//初始為0,狀態(tài)是上面幾種,標(biāo)識當(dāng)前節(jié)點(diǎn)在隊(duì)列中的狀態(tài)
        volatile int waitStatus;

        /**
         * Link to predecessor node that current node/thread relies on
         * for checking waitStatus. Assigned during enqueuing, and nulled
         * out (for sake of GC) only upon dequeuing.  Also, upon
         * cancellation of a predecessor, we short-circuit while
         * finding a non-cancelled one, which will always exist
         * because the head node is never cancelled: A node becomes
         * head only as a result of successful acquire. A
         * cancelled thread never succeeds in acquiring, and a thread only
         * cancels itself, not any other node.
         */
    	//前置節(jié)點(diǎn)
        volatile Node prev;

        /**
         * Link to the successor node that the current node/thread
         * unparks upon release. Assigned during enqueuing, adjusted
         * when bypassing cancelled predecessors, and nulled out (for
         * sake of GC) when dequeued.  The enq operation does not
         * assign next field of a predecessor until after attachment,
         * so seeing a null next field does not necessarily mean that
         * node is at end of queue. However, if a next field appears
         * to be null, we can scan prev's from the tail to
         * double-check.  The next field of cancelled nodes is set to
         * point to the node itself instead of null, to make life
         * easier for isOnSyncQueue.
         */
    	//后置節(jié)點(diǎn)
        volatile Node next;

        /**
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         */
    	//當(dāng)線程對象
        volatile Thread thread;

        /**
         * Link to next node waiting on condition, or the special
         * value SHARED.  Because condition queues are accessed only
         * when holding in exclusive mode, we just need a simple
         * linked queue to hold nodes while they are waiting on
         * conditions. They are then transferred to the queue to
         * re-acquire. And because conditions can only be exclusive,
         * we save a field by using special value to indicate shared
         * mode.
         */
        Node nextWaiter;

        /**
         * Returns true if node is waiting in shared mode.
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * Returns previous node, or throws NullPointerException if null.
         * Use when predecessor cannot be null.  The null check could
         * be elided, but is present to help the VM.
         *
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

    node節(jié)點(diǎn)就是每一個等待執(zhí)行的線程。還有一個waitState狀態(tài)字段,標(biāo)識當(dāng)前等待中的線程狀態(tài)

根據(jù)node節(jié)點(diǎn) 繪畫一個aqs基本結(jié)構(gòu)圖

如何理解AQS源碼

     解釋:state為狀態(tài)位,aqs為同步器。有head 和tail兩個 頭 尾節(jié)點(diǎn),當(dāng)state = 1時,表明同步器被占用(或者說當(dāng)前有線程持有了同一個對象的鎖),將后續(xù)線程添加到隊(duì)列中,并用雙向鏈表連接,遵循FIFO。

     (2)以ReentrantLock的實(shí)現(xiàn)分析。因?yàn)樗矊?shí)現(xiàn)了Lock 并內(nèi)部持有同步器sync和AQS(以銀行柜臺例子)

     new ReentrantLock()或 new ReentrantLock(false)時,創(chuàng)建的是非公平鎖,而 ReentrantLock對象內(nèi)部還有 兩個類 分別為公平同步器和非公平同步器

static final class NonfairSync extends Sync
//公平鎖 有一個判斷隊(duì)列中是否有排隊(duì)的線程,這是與上面鎖不同的獲取方式
static final class FairSync extends Sync

    公平鎖解釋:先到先得,新線程在獲取鎖時,如果這個同步器的等待隊(duì)列中已經(jīng)有線程在等待,那么當(dāng)前線程會先進(jìn)入等待隊(duì)列;

    非公平鎖解釋:新進(jìn)來的線程不管是否有等待的線程,如果可以獲取鎖,則立刻占有鎖。

    這里還有一個關(guān)鍵的模板設(shè)計(jì)模式: 在查詢aqs的tryAcquire方法時發(fā)現(xiàn),該方法直接拋出異常,這就是典型的模板設(shè)計(jì)模式,強(qiáng)制要求子類重寫該方法。否則不讓用

    1.1  當(dāng)線程a到柜臺辦理業(yè)務(wù)時,會調(diào)用sync 的lock,即 a線程調(diào)用lock方法

final void lock() {
    //利用cas將當(dāng)前對象的state 從0 設(shè)置成1,當(dāng)然里面還有一個偏移量
    //意思就是如果是0 就設(shè)置為1成功返回true
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

    因?yàn)槭堑谝粋€運(yùn)行的線程,肯定是true所以,將當(dāng)前運(yùn)行的線程設(shè)置為a,即a線程占用了同步器,獲取了鎖

    1.2 當(dāng)b線程運(yùn)行l(wèi)ock時,發(fā)現(xiàn)不能將0設(shè)置成1(cas思想),就會運(yùn)行acquire(1)方法

public final void acquire(int arg) {
    //這里用到了模板設(shè)計(jì)模式,強(qiáng)制子類實(shí)現(xiàn)該方法
    //因?yàn)槟J(rèn)使用非公平鎖,所以看NonfairSync 
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

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() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

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

//該方法就是非公平鎖執(zhí)行 等待的方法
final boolean nonfairTryAcquire(int acquires) {
    //獲取當(dāng)前b線程
    final Thread current = Thread.currentThread();
    //獲取當(dāng)前鎖的狀態(tài)是1,因?yàn)閍線程已經(jīng)獲取,并將state修改為1
    int c = getState();
    //有可能b在設(shè)置state時,a正辦理,到這兒時,a辦理完了。state為0了。
    if (c == 0) {
        //樂觀的將state 從0 修改為 1
        if (compareAndSetState(0, acquires)) {
            //設(shè)置當(dāng)前獲取鎖的線程為b
            setExclusiveOwnerThread(current);
            return true;
        }
    }

    //有可能 a線程辦完業(yè)務(wù)。又回頭辦理了一個,所以當(dāng)前線程持有鎖的線程依舊是a
    else if (current == getExclusiveOwnerThread()) {
        //2
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        //設(shè)置state的值
        setState(nextc);
        return true;
    }
    //如果b線程走到這里,就證明b必須到等待隊(duì)列里去了
    return false;
}

     再來看邏輯運(yùn)算符后面的邏輯

private Node addWaiter(Node mode) {
    //實(shí)例化一個節(jié)點(diǎn),并將b 和 節(jié)點(diǎn)類型封裝成node
    Node node = new Node(Thread.currentThread(), mode);
    //等待隊(duì)列為null 所以tail初始化肯定是null
    //如果是線程c在b之后進(jìn)來,tail就是b 節(jié)點(diǎn)
    Node pred = tail;
    //c節(jié)點(diǎn)之后都走這個方法
    if (pred != null) {
        //node的前置為tail
        //c 的前置設(shè)置為b
        node.prev = pred;
        //cas樂觀,比較 如果當(dāng)前節(jié)點(diǎn)仍然是b 就將b 設(shè)置成c
        //b就是tail尾節(jié)點(diǎn),將tail設(shè)置成c
        //這里根據(jù)源碼可知,就是將tail的值設(shè)置成c 并不影響pred的值,還是b
        if (compareAndSetTail(pred, node)) {
            //b 的下一個節(jié)點(diǎn)設(shè)置成c
            pred.next = node;
            return node;
        }
    }
    //線程b 入等待隊(duì)列
    enq(node);
    return node;
}

//入隊(duì)列方法
private Node enq(final Node node) {
    //該方法類似于while(true)
    for (;;) {
        //獲取tail節(jié)點(diǎn)
        Node t = tail;
        //初始化鎖等待隊(duì)列
        if (t == null) { // Must initialize
            //設(shè)置頭部節(jié)點(diǎn)為新的節(jié)點(diǎn)
            //這里看出,鎖等待隊(duì)列的第一個節(jié)點(diǎn)并非b,而是一個空node,該node為站位節(jié)點(diǎn)或者叫哨兵節(jié)點(diǎn)
            if (compareAndSetHead(new Node()))
                //將頭尾都指向該節(jié)點(diǎn)
                tail = head;
        } else {
            //第二次循環(huán)時,t為空node,將b的前置設(shè)置為空node
            node.prev = t;
            //設(shè)置tail節(jié)點(diǎn)為b節(jié)點(diǎn)
            if (compareAndSetTail(t, node)) {
                //空node節(jié)點(diǎn)的下一個節(jié)點(diǎn)為b node節(jié)點(diǎn)
                t.next = node;
                return t;
            }
        }
    }
}
/**
 * CAS head field. Used only by enq.
 */
private final boolean compareAndSetHead(Node update) {
    return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

     以上b線程的進(jìn)入等待隊(duì)列的操作就完成了 ,但線程還是活躍的,如何阻塞的呢?

     下面接著看acquireQueued方法

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        //自旋執(zhí)行
        for (;;) {
            //如果是b線程,這里p就是b節(jié)點(diǎn)的前置節(jié)點(diǎn)
            final Node p = node.predecessor();
            //空節(jié)點(diǎn)就是head節(jié)點(diǎn),但又調(diào)用了一次tryAcquire方法,想再嘗試獲取鎖資源
            //如果a線程未處理完,那么這里返回false
            //如果a線程處理完成,那么這里就可以獲取到鎖
            if (p == head && tryAcquire(arg)) {
                //將head設(shè)置成b節(jié)點(diǎn)
                setHead(node);
                //原空節(jié)點(diǎn)的下連接斷開
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //第一次空節(jié)點(diǎn)進(jìn)入should方法。返回false
            //當(dāng)?shù)诙窝h(huán)到此處should方法返回true
            //執(zhí)行parkAndCheckInterrupt方法,會將當(dāng)前線程park,并獲取b線程的中斷狀態(tài),如果未中斷返回false,并再次自旋一次 ,中斷為true
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    //head節(jié)點(diǎn)就是空節(jié)點(diǎn)所以w=0
    //空節(jié)點(diǎn)第二次進(jìn)入時就是-1
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        return true;
    //如果b節(jié)點(diǎn)狀態(tài)是其他,則將節(jié)點(diǎn)連接變化一下
    if (ws > 0) {
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        //ws = 0時,使用cas將驗(yàn)證pred 和ws 的值,是空節(jié)點(diǎn)和0  并將ws修改為-1
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

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

     以上b線程未獲取鎖 并被掛起的操作就完成了

    1.3  當(dāng)a線程調(diào)用unlock方法時:

public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
    //判斷a線程是否完成業(yè)務(wù)。并釋放鎖,state=0
    if (tryRelease(arg)) {
        //獲取頭部節(jié)點(diǎn),就是空節(jié)點(diǎn)
        Node h = head;
        //空節(jié)點(diǎn)在b獲取鎖時,狀態(tài)變更為-1,所以這里是true
        if (h != null && h.waitStatus != 0)
            //喚醒線程
            unparkSuccessor(h);
        return true;
    }
    return false;
}

//aqs父類的模板方法,強(qiáng)制要求子類實(shí)現(xiàn)該方法
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

protected final boolean tryRelease(int releases) {
    //將鎖的狀態(tài)設(shè)置為0
    int c = getState() - releases;
    //判斷當(dāng)前線程與 鎖的獨(dú)占線程是否一致
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    //所得狀態(tài)標(biāo)識
    boolean free = false;
    if (c == 0) {
        free = true;
        //如果state=0證明a完成了業(yè)務(wù)。那么鎖的獨(dú)占狀態(tài)就應(yīng)該恢復(fù)為null
        setExclusiveOwnerThread(null);
    }
    //恢復(fù)鎖的state狀態(tài)
    setState(c);
    return free;
}

    注意:這里state是減1操作。如果ReentrantLock不斷可重入,那么這里是不能一次就歸零的。所以才會有ReentrantLock 調(diào)了幾次lock 就是要調(diào)幾次unlock

    a線程喚醒b線程

private void unparkSuccessor(Node node) {
    
    int ws = node.waitStatus;
    if (ws < 0)
        //空節(jié)點(diǎn)-1,設(shè)置成0
        compareAndSetWaitStatus(node, ws, 0);

	//獲取b節(jié)點(diǎn),非null 且 waitState=0
    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)
        //將b線程喚醒
        LockSupport.unpark(s.thread);
}

     而 b線程還在acquireQueued方法里自旋呢,不過自旋后就會獲取鎖。

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        //b線程在a未釋放鎖之前一直在自旋,
        for (;;) {
            final Node p = node.predecessor();
            //當(dāng)a釋放鎖后,b獲取到鎖,將state設(shè)置為1
            //并將空節(jié)點(diǎn)的所有連接斷開等待GC回收
            //并返回當(dāng)前線程 b 的中斷狀態(tài)
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //park當(dāng)前線程b 并獲取b的中斷狀態(tài),肯定是false,且調(diào)用的是帶參的native方法,多次調(diào)用會重置b線程的中斷狀態(tài)
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
//調(diào)用該方法的if判斷如果進(jìn)入了。會將b 中斷,并在不斷循環(huán)中再重置中斷狀態(tài)為false

     1.4 c線程的執(zhí)行流程與b線程類似。會將b節(jié)點(diǎn)充等待隊(duì)列中移除,遵循FIFO

“如何理解AQS源碼”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI