帶你看看Java-AQS同步器 源碼解讀<一>獨(dú)占鎖加鎖

別人都祝你開(kāi)心快樂(lè),我只愿你歷盡山河,覺(jué)得人間值得

AQS 全稱 AbstractQueuedSynchronizer 中文翻譯同步器 同步器是java中各種鎖實(shí)現(xiàn)的基礎(chǔ),非常重用的 。比如我們線程池里面的Worker 類 我們的重入鎖ReentrantLock,信號(hào)量Semaphore,CountDownLatch 等

  1. Java-AQS同步器 源碼解讀<一>獨(dú)占鎖加鎖
  2. Java-AQS同步器 源碼解讀<二>獨(dú)占鎖解鎖
  3. Java-AQS同步器 源碼解讀<三>共享鎖
  4. Java-AQS同步器 源碼解讀<四>-條件隊(duì)列上
  5. Java-AQS同步器 源碼解讀<五>-條件隊(duì)列下

我們一步步的來(lái)看 是怎么實(shí)現(xiàn)的
首先 我們先看下 這個(gè)類文件

abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
    implements java.io.Serializable

從文件中我們看出 AbstractQueuedSynchronizer是個(gè)抽象類繼承了AbstractOwnableSynchronizer抽象類
那我們就去看看AbstractOwnableSynchronizer有什么

AbstractOwnableSynchronizer

public abstract class AbstractOwnableSynchronizer
    implements java.io.Serializable {

    /** Use serial ID even though all fields transient. */
    private static final long serialVersionUID = 3737899427754241961L;

    /**
     * 構(gòu)造器 
     */
    protected AbstractOwnableSynchronizer() { }

    /**
     * The current owner of exclusive mode synchronization.
    *  從上面的英文翻譯 和下面字段的命名 我們能知道 這個(gè)是一個(gè)線程對(duì)象 
   *  是獨(dú)占鎖模式下  同步器的當(dāng)前擁有者線程
     */
    private transient Thread exclusiveOwnerThread;

    /**
     * 設(shè)置 獨(dú)占鎖 同步器的擁著線程 沒(méi)什么好說(shuō)的
     */
    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

    /**
     *  獲取當(dāng)前 同步器的擁著線程  也沒(méi)什么
     */
    protected final Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }

從以上的代碼中 我們可以分析得到 AQS 基礎(chǔ)這個(gè)類 是為了 得到獨(dú)占鎖模式擁有鎖的線程 方便監(jiān)控

AbstractQueuedSynchronizer

那看完 上面的代碼 那我們進(jìn)入AbstractQueuedSynchronizer 里面看下 這個(gè)類里面又有什么
從源碼中 我們可以將AQS的內(nèi)部屬性分為4類

  • 同步器的簡(jiǎn)單屬性,
  • 同步隊(duì)列屬性,
  • 條件隊(duì)列屬性,
  • 公用的Node類,和一個(gè)ConditionObject類
    一個(gè)一個(gè)來(lái)看吧
    先看Node這個(gè)類 這個(gè)類很重要 它即是同步隊(duì)列的節(jié)點(diǎn) 也是條件隊(duì)列的節(jié)點(diǎn)

AQS 內(nèi)部Node

/**
     * 等待隊(duì)列的節(jié)點(diǎn)類,通過(guò)Node 可以實(shí)現(xiàn)2個(gè)隊(duì)列 一個(gè)是線程同步隊(duì)列(雙向隊(duì)列) 一個(gè)是條件線程隊(duì)列(單向隊(duì)列)
     */
    static final class Node {
        /**
         * 標(biāo)識(shí)這個(gè)節(jié)點(diǎn)用于共享模式
         * Marker to indicate a node is waiting in shared mode
         */
        static final AbstractQueuedSynchronizer.Node SHARED = new AbstractQueuedSynchronizer.Node();
        /**
         * 標(biāo)識(shí)這個(gè)節(jié)點(diǎn)用于 獨(dú)占模式(排它 反正一個(gè)意思)
         * Marker to indicate a node is waiting in exclusive mode
         */
        static final AbstractQueuedSynchronizer.Node EXCLUSIVE = null;

        /** 下面是 waitStatus 的幾個(gè)常量值  */

        /**
         * 表明等待線程已經(jīng)取消
         * waitStatus value to indicate thread has cancelled
         */
        static final int CANCELLED = 1;
        /**
         * 表述如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)狀態(tài)是 SIGNAL  那么就可以阻塞當(dāng)前自己的線程 不用去爭(zhēng)搶資源了  沒(méi)用 不然會(huì)一直嘗試去獲取資源 
         * waitStatus value to indicate successor's thread needs unparking
         */
        static final int SIGNAL = -1;
        /**
         * 線程在條件隊(duì)列中等待
         * waitStatus value to indicate thread is waiting on condition
         */
        static final int CONDITION = -2;
        /**
         * 共享模式下  無(wú)條件傳播   該狀態(tài)的進(jìn)程處于可運(yùn)行狀態(tài)
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
        static final int PROPAGATE = -3;
        /**
         * 當(dāng)前node 狀態(tài)
         */
        volatile int waitStatus;

        /**
         * 獨(dú)占模式下 節(jié)點(diǎn)指向的上一個(gè)節(jié)點(diǎn)
         */
        volatile AbstractQueuedSynchronizer.Node prev;

        /**
         * 獨(dú)占模式下 節(jié)點(diǎn)指向的下一個(gè)節(jié)點(diǎn)
         */
        volatile AbstractQueuedSynchronizer.Node next;

        /**
         * 入隊(duì)時(shí)的線程
         * The thread that enqueued this node.  Initialized on
         * construction and nulled out after use.
         */
        volatile Thread thread;

        /**
         * condition 條件隊(duì)列中的后繼節(jié)點(diǎn)
         */
        AbstractQueuedSynchronizer.Node nextWaiter;

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

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

        Node() {    // Used to establish initial head or SHARED marker
        }

        /**
         * 用于addWaiter
         */
        Node(Thread thread, AbstractQueuedSynchronizer.Node mode) {
            this.nextWaiter = mode;
            this.thread = thread;
        }

        /**
         * 用于Condition
         */
        Node(Thread thread, int waitStatus) {
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

AQS 實(shí)例屬性

看完了 Node 節(jié)點(diǎn) 我看看下AQS 本身的實(shí)例屬性 有哪些

/**
     * 同步隊(duì)列的頭  初始化 或者setHead方法可修改
     */
    private transient volatile Node head;

    /**
     *  同步隊(duì)列的尾節(jié)點(diǎn) 通過(guò)enq方法去修改尾節(jié)點(diǎn) 后面會(huì)分析到
     */
    private transient volatile Node tail;

    /**
     *  同步器的狀態(tài)   這里 可以去 去看下 Semaphore 這個(gè)類 我們初始化的時(shí)候 實(shí)際 
     上就是調(diào)用的setState 方法 給同步器的狀態(tài)賦值的 每個(gè)線程獲取的時(shí)候都會(huì)去消 耗這個(gè)值 達(dá)到控制并發(fā)效果
     */
    private volatile int state;

    /**
     *  獲取同步器狀態(tài)
     */
    protected final int getState() {
        return state;
    }

    /**
     *  同步器狀態(tài)賦值
     */
    protected final void setState(int newState) {
        state = newState;
    }

看完了 上面的2中模式 解鎖下獨(dú)占和共享什么意思吧
獨(dú)占的意思的同一時(shí)刻 只能有一個(gè)線程可以獲得鎖 其余的都排隊(duì)阻塞,釋放資源的時(shí)候也只有線程可以釋放 比如重入鎖ReentrantLock
共享就是允許多個(gè)線程獲得同一個(gè)鎖,并且可以設(shè)置獲取鎖的線程數(shù)量 比如我 用Semaphore初始狀態(tài)設(shè)置為4 每個(gè)線程獲取2個(gè) 那同時(shí)可以有2個(gè)線程獲取鎖

AQS 獨(dú)占鎖

看完了上面的一些接受 下面我們來(lái)跟著代碼去分析下獨(dú)占鎖 是怎么實(shí)現(xiàn)的

獨(dú)占鎖 加鎖

  • acquire方法
    為什么首先 我們要看這個(gè)方法呢,因?yàn)檫@是鎖獲取資源的入口,那我們就看下代碼,用ReentrantLock來(lái)舉例看看
我們使用ReentrantLock 開(kāi)始加鎖
   public void lock() {
        sync.lock();
    }
我們看下sync.lock 是什么
    abstract static class Sync extends AbstractQueuedSynchronizer {
        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();
     ......
     }
可以看到sync的lock 方法也是個(gè)抽象方法 應(yīng)該是Sync的子類去實(shí)現(xiàn)的
那我們就看下ReentrantLock的構(gòu)造方法
    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
其中得到ReentrantLock 默認(rèn)構(gòu)造函數(shù)中  sync的實(shí)現(xiàn)是NonfairSync公平鎖,那我們繼續(xù)看NonfairSync這個(gè)類

/**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
    }
如果 我們找到了Sync的抽象方法lock 在子類中的實(shí)現(xiàn),其實(shí)就是執(zhí)行了acquire 方法
acquire方法在那呢 ?
FairSync 繼承了內(nèi)部抽象類 Sync類 而從上面的截取的代碼中
我們看到Sync類其實(shí)就繼承了AbstractQueuedSynchronizer 類  這樣最終我們會(huì)定位到AQS類中acquire方法

那下面我們就來(lái)看下acquire 這個(gè)方法

/*
*以獨(dú)占鎖的方式 去獲取資源 響應(yīng)中斷
*/
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  • tryAcquire(arg) 方法
protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

首先我們看到這個(gè)AQS里面 雖然寫(xiě)了tryAcquire方法 但是 拋出一個(gè)異常,為什么要這么做呢 其實(shí)JDK 作者 是為了方便開(kāi)發(fā)者 我什么這么說(shuō)呢 因?yàn)锳QS是個(gè)抽象類 這個(gè)方法其實(shí)可以寫(xiě)成抽象方法 讓子類來(lái)實(shí)現(xiàn) 但是這帶來(lái)一個(gè)問(wèn)題 因?yàn)锳QS是很多鎖實(shí)現(xiàn)的基礎(chǔ) 如果寫(xiě)成抽象方法 子類就必須實(shí)現(xiàn) 但是可能有些鎖 并不需要實(shí)現(xiàn)這個(gè)方法 沒(méi)用。所以AQS里面這么去寫(xiě),是OK的,因?yàn)橐褂玫倪@個(gè)功能的鎖 必須去實(shí)現(xiàn)重寫(xiě)這個(gè)方法,不讓就報(bào)錯(cuò) ,不要使用到這個(gè)方法的子類 不用管。這樣的思想 我們可以去參考 在以后得開(kāi)發(fā)中!

那我們?nèi)タ聪翿eentrantLock 類中是否是這樣做的
看下代碼:

image.png

從上面的截圖中 我們可以看到 確實(shí)是實(shí)現(xiàn)了的 ReentrantLock 有一個(gè)抽象類Sync 2個(gè)靜態(tài)類 且繼承抽象類 Sync 繼承了我們AQS 并且實(shí)現(xiàn)釋放資源的方法,加鎖去獲取資源的方法tryAcquire 分別由2個(gè)子類實(shí)現(xiàn)就 一個(gè)實(shí)現(xiàn)FairSync 公平鎖 一個(gè)實(shí)現(xiàn)NonfairSync非公平鎖

tryAcquire 方法是嘗試以獨(dú)占的方式去獲取資源
具體各個(gè)鎖里面的方法實(shí)現(xiàn) 自己可以去看下 我們還是看下吧ReentrantLock

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            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;
        }

上面的代碼是非公平鎖 實(shí)現(xiàn)的TryAcquire方法的版本 其實(shí)也很好讀懂就是判斷我們之前提到過(guò)的AQS里面的state ,上面我提到過(guò)ReentrantLock 默認(rèn)是非公平鎖,初始化的state值是0,這個(gè)一開(kāi)始用getState 去獲取方法state當(dāng)前的值,如果值等于0,說(shuō)明鎖沒(méi)有其他線程占用,可以獲取鎖,使用CAS原子操作State 新增1,如果CAS 成功就設(shè)置當(dāng)前鎖的所屬的線程 這個(gè)一開(kāi)始我描述過(guò)AbstractOwnableSynchronizer里面的功能 ,如果獲取的時(shí)候state不為0,就判斷下當(dāng)前的線程是否等于鎖所屬的線程,因?yàn)槭仟?dú)占的 ,如果相等就把State 再次加1,這個(gè)判斷也就是說(shuō) 我們調(diào)了同個(gè)線程多次lock了,這個(gè)時(shí)非公平鎖的代碼,公平鎖的實(shí)現(xiàn)和上面的差不多 就是多了一個(gè)隊(duì)列的判斷,要從阻塞隊(duì)列里面的頭部節(jié)點(diǎn)開(kāi)始一個(gè)個(gè)地排隊(duì)獲取,而非公平鎖就沒(méi)有,只要釋放了 看誰(shuí)先來(lái) 就誰(shuí)先獲取到鎖,看多不公平啊,哈哈!

是否滿足,如果滿足就返回True說(shuō)明獲取到了鎖,不滿足就返回false acquire后面的方法會(huì)繼續(xù)執(zhí)行

好的 我們繼續(xù)回到acquire方法中 如果tryacquire方法返回false 也就是沒(méi)有獲取到鎖,執(zhí)行下一個(gè)方法acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 那進(jìn)入這個(gè)方法的時(shí)候 又先執(zhí)行addWaiter 后執(zhí)行acquireQueued

  • addWaiter(Node.EXCLUSIVE)方法
 /**
     *  這個(gè)方法就是加入當(dāng)前節(jié)點(diǎn)到隊(duì)列的尾節(jié)點(diǎn)
     */
    private Node addWaiter(Node mode) {
        /*構(gòu)建node 節(jié)點(diǎn)  還記得 我們上面寫(xiě)的方法 用于addWaiter么 可以上面去看下
        這里的node 幾點(diǎn)里面的nextWaiter 這個(gè)字段被復(fù)用了,在排他鎖模式下用于記錄鎖類型*/
        Node node = new Node(Thread.currentThread(), mode);
        /*Try the fast path of enq; backup to full enq on failure
        從上面的英文注解上面 我們能得到下面的方法是先嘗試快速加入隊(duì)尾,
        成功則返回當(dāng)前節(jié)點(diǎn),如果失敗就進(jìn)入的 enq方法  最后返回節(jié)點(diǎn)*/
        Node pred = tail;
        if (pred != null) {
            //當(dāng)前節(jié)點(diǎn)的頭節(jié)點(diǎn)指向隊(duì)列的尾部節(jié)點(diǎn),相當(dāng)于加入到最后了
            node.prev = pred;
            //CAS 賦值隊(duì)列尾部節(jié)點(diǎn)
            if (compareAndSetTail(pred, node)) {
             // 如果成功將尾部節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)指向我們新加的節(jié)點(diǎn),因?yàn)槭请p向鏈表,所以要互相指一下的 
                pred.next = node;
                return node;
            }
        }
      // 如果 尾部節(jié)點(diǎn)是null 或者CAS賦值尾部節(jié)點(diǎn)失敗,則進(jìn)入enq 方法,其實(shí)就是采用了自旋的方法加入 走我們進(jìn)去看下怎么做的
        enq(node);
        return node;
    }

-enq 方法
老規(guī)矩 上源碼

/*
* 使用自旋的方法 加入尾部節(jié)點(diǎn)
*/
private Node enq(final Node node) {
        //無(wú)條件的循環(huán) 自旋 好好理解下這個(gè)方法 其實(shí)循環(huán)只有一個(gè)出口 就是成功加入尾部節(jié)點(diǎn)返回
        for (;;) {
            Node t = tail;
            if (t == null) { // 這邊尾部節(jié)點(diǎn)是null 說(shuō)明整個(gè)隊(duì)列都是空的 必須初始化一下
/*CAS 賦值一個(gè)頭部節(jié)點(diǎn) 如果成功 就頭節(jié)點(diǎn)賦值給尾節(jié)點(diǎn),
也很好理解初始化么 沒(méi)有任何節(jié)點(diǎn),當(dāng)然頭就是尾,尾就是頭,不理解的可以看看 鏈表結(jié)構(gòu)如果CAS失敗,
就不做什么 反正又出不來(lái)這個(gè)循環(huán),就繼續(xù)循壞吧,總會(huì)成功的,不要覺(jué)得這邊會(huì)死循環(huán),因?yàn)榫退鉉AS不成功,
可能是有別的線程修改了值導(dǎo)致的,下次循環(huán)的時(shí)候就走不到這邊了 t也就是尾節(jié)點(diǎn)就不為null了,走到下面的判斷*/
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
 //走呀走 終于到這邊了,看看這部代碼 是不是很熟悉,好好想想,往上面看看,其實(shí)addWaiter的方法是一樣的,
//只不過(guò)這邊做了自旋操作,保證了一定加入隊(duì)尾成功
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

ok 看到這邊 小伙伴們 不知道有沒(méi)有暈哈,不管怎么樣,革命尚未成功,繼續(xù)哈,好的 我們回到acquire中

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

上面我們看了tryAcquire方法 和addWaiter方法,那最后我們看下acquireQueued方法是什么 acquireQueued方法的參數(shù)一個(gè)就是addWaiter 返回加入尾部的節(jié)點(diǎn),還有一個(gè)arg是我們各個(gè)實(shí)現(xiàn)鎖方法傳進(jìn)來(lái)的

-acquireQueued方法

 /**
     * 當(dāng)前節(jié)點(diǎn)加入的隊(duì)尾后,嘗試自旋的方式去獲取資源,
  * 這個(gè)方法還有個(gè)作用就是自己的前置節(jié)點(diǎn)變?yōu)镾IGNAL 這樣他自己就能阻塞了
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;//表述是否拿到資源失敗    也就是說(shuō)false表述拿到資源了
        try {
//標(biāo)記 是否執(zhí)行中斷 為什么有這個(gè)是因?yàn)榇朔椒](méi)有拋出異常 如果內(nèi)部發(fā)生異常 要通知上一級(jí)調(diào)用,所有有此標(biāo)識(shí)
            boolean interrupted = false;
            for (;;) {//這邊又是自旋的方法 方法出口只有一個(gè) 就是獲取到資源
/*
P 是當(dāng)前節(jié)點(diǎn)node的前一個(gè)節(jié)點(diǎn) 這邊判斷的意思 是如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)就是頭部節(jié)點(diǎn),那就嘗試去獲取鎖資源,
如果能獲取到 說(shuō)明頭節(jié)點(diǎn)已經(jīng)釋放了鎖,那就迅速讓自己成為隊(duì)列的頭部節(jié)點(diǎn),讓之前的頭部節(jié)點(diǎn)next指向null 
是為了方便GC的回收,然后賦值failed 為true 表示已經(jīng)獲取到資源,并且返回中斷狀態(tài)
 */
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
//如果P不是head節(jié)點(diǎn)或者是head節(jié)點(diǎn)但是嘗試獲取資源失敗,說(shuō)明鎖資源還沒(méi)被釋放,那就執(zhí)行到這邊
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

那我們?cè)谶M(jìn)入shouldParkAfterFailedAcquire 方法中看看 是什么

-shouldParkAfterFailedAcquire 方法

 /**
     * 更新prev節(jié)點(diǎn)狀態(tài) ,并根據(jù)prev節(jié)點(diǎn)狀態(tài)判斷是否自己當(dāng)前線程需要阻塞
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;// node的prev節(jié)點(diǎn)的狀態(tài)
        if (ws == Node.SIGNAL)
         //  如果SIGNAL 就返回true 就會(huì)執(zhí)行到parkAndCheckInterrupt方法里面 
            return true;
        if (ws > 0) {
/* 
* 如果ws 大于0 這里是只能為1,如果是1說(shuō)明線程已經(jīng)取消,相當(dāng)于無(wú)效節(jié)點(diǎn)
* 者說(shuō)明 當(dāng)前node 節(jié)點(diǎn)加入到了一個(gè)無(wú)效節(jié)點(diǎn)后面,那這個(gè)必須處理一下
 node.prev = pred = pred.prev 
* 這個(gè)操作 我們拆解下來(lái)看,下看 pred = pred.prev這個(gè)的意思是把prev節(jié)點(diǎn)的prev*節(jié)點(diǎn) 賦值給prev節(jié)點(diǎn)
*后面再看 node.prev = pred  聯(lián)合 剛才的賦值 這個(gè)的意思就是把prev節(jié)點(diǎn)的prev節(jié)點(diǎn)和node關(guān)聯(lián)起來(lái),
*原因我上面也說(shuō)了因?yàn)閜re節(jié)點(diǎn)線程取消了,所以node節(jié)點(diǎn)不能指向pre節(jié)點(diǎn) 只能一個(gè)一個(gè)的往前找,
*找到waitStatus 小于或者等于0的結(jié)束循環(huán)最后再把找到的pre節(jié)點(diǎn)執(zhí)行node節(jié)點(diǎn) ,這樣就跳過(guò)了所有無(wú)效的節(jié)點(diǎn)
*/
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
           /* 
*這邊的操作就是把pred 節(jié)點(diǎn)的狀態(tài)設(shè)置為SIGNAL,這樣返回false 這樣可以返回到上面的自旋中 
*再次執(zhí)行一次,如果還是獲取不到鎖,那么又回到當(dāng)前的shouldParkAfterFailedAcquire方法 執(zhí)行到方法最上面的判斷
*/
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

-parkAndCheckInterrupt方法
回到剛才 如果shouldParkAfterFailedAcquire方法返回true 那么就會(huì)執(zhí)行parkAndCheckInterrupt方法
這個(gè)方法很簡(jiǎn)單

/**
     * Convenience method to park and then check if interrupted
     * @return {@code true} if interrupted
     */
    private final boolean parkAndCheckInterrupt() {
       /*
       * 這邊線程阻塞,只有2中方式喚醒當(dāng)前線程,
       * 一種方式就是 當(dāng)前線程發(fā)生中斷
       * 另外一個(gè)情況就是 資源釋放的時(shí)候會(huì)調(diào)unpark 方法 喚醒當(dāng)前的線程 這個(gè)會(huì)在下一篇會(huì)講到
      */
        LockSupport.park(this);
        return Thread.interrupted();
    }

沒(méi)什么好說(shuō)的 就是阻塞當(dāng)前線程,并且檢查當(dāng)前線程有沒(méi)有過(guò)中斷 返回 正常的話 只有release釋放資源后 會(huì)喚醒線程 但是線程發(fā)生中斷也是可以的 所以這邊要堅(jiān)持下 是那種情況 喚醒當(dāng)前線程的方式 并返回

最后的最后我們?cè)俅位氐絼偛诺姆椒?/p>

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
最后這邊 currentThread做出線程中斷 如果上面都返回true的話
static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

不知道 大家有沒(méi)有了解acquire 怎么去實(shí)現(xiàn)獲取資源的了

如果還是不知道 AQS里面的獨(dú)占鎖怎么加鎖的 最后做下簡(jiǎn)短的總結(jié):
1.首先第一步 用tryAcquire方法嘗試去獲取資源 此方法由各個(gè)繼承類重寫(xiě),如果成功就直接返回 獲取鎖成功,如果失敗 則進(jìn)入步驟2
2.進(jìn)入addWaiter方法 這個(gè)方法主要做的就是把當(dāng)前的線程包裝成node節(jié)點(diǎn)放入阻塞隊(duì)列的隊(duì)尾,里面有enq方法里面有自旋的操作
3.然后進(jìn)入acquireQueued方法,入?yún)⒁皇莂ddWaiter方法返回的no的節(jié)點(diǎn),入?yún)⒍褪莂cquire 方法的參數(shù)arg,因?yàn)槔锩孢€要調(diào)用tryAcquire方法,所以此參數(shù)要傳的,這個(gè)方法主要做的就是 嘗試自旋去獲取資源,但是嘗試獲取資源也是條件的 就是當(dāng)前node節(jié)點(diǎn)的prev節(jié)點(diǎn)是head,這樣就避免了無(wú)腦去循環(huán)去獲取資源,這個(gè)方法里面還做了一個(gè)事情 就是判斷下 如果當(dāng)前node 節(jié)點(diǎn)的prev節(jié)點(diǎn) waitStatus 如果是SIGNAL 那就直接執(zhí)行下面的parkAndCheckInterrupt方法去阻塞當(dāng)前線程,為什么會(huì)這么寫(xiě)呢,因?yàn)槿绻?dāng)前節(jié)點(diǎn)狀態(tài)是SIGNAL 說(shuō)明自己已經(jīng)獲取過(guò)鎖,并且沒(méi)獲取到,所以后面的節(jié)點(diǎn) 就不要再去獲取了 直接阻塞吧!
4.最后 如果阻塞的線程 有中斷,那會(huì)執(zhí)行到最后一步selfInterrupt中,就是做出線程中斷,好讓當(dāng)前的線程 后面的方法 知道這個(gè)中斷,并做出回應(yīng),如果不清楚這個(gè)的話 就要好好去了解下線程的interrupt 的作用 和三個(gè)常用的方法

好的簡(jiǎn)單的總結(jié)完畢,如果還是不了解 自己一遍看著我的解鎖一個(gè)看著源碼,自己理解下,我相信一定會(huì)有收獲的!加油!

夜已深,全文手寫(xiě),碼字不容易 有錯(cuò)誤的地方 希望大家多多指出,覺(jué)得還行的話 給個(gè)贊就好了 多謝各位捧場(chǎng) AQS 內(nèi)容太多,明天繼續(xù)寫(xiě)?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容