最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

AQS實現(xiàn)的ReentrantLock全過程

 更新時間:2026年03月24日 09:39:00   作者:隔壁小鄧  
這篇文章主要介紹了AQS實現(xiàn)的ReentrantLock全過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

這里的源碼用的Java8版本

lock方法#

當(dāng)ReentrantLock類的實例對象嘗試獲取鎖的時候,調(diào)用lock方法

會進入sync的lock方法,其中Sync是ReentrantLock的一個內(nèi)部類,ReentrantLock構(gòu)造方法會默認使用非公平鎖NonfairSync,這個類是繼承于Sync的

        final void lock() {
            if (!initialTryLock())
                acquire(1);
        }
// 其中Sync的initialTryLock是抽象方法,需要看非公平鎖實現(xiàn)方法

[!TIP]
在這里是第一次嘗試獲取鎖

由于ReentrantLock是個可重入鎖,判斷里有重入的判斷

final boolean initialTryLock() {
            Thread current = Thread.currentThread();
			// 獲取當(dāng)前線程的對象
            if (compareAndSetState(0, 1)) { // first attempt is unguarded
			// 用CAS比較state狀態(tài)是否為0(無人持有鎖),如果是,就轉(zhuǎn)為1(獲取到鎖)
                setExclusiveOwnerThread(current);
			// 將當(dāng)前進程設(shè)置為擁有鎖的線程
                return true;
            } else if (getExclusiveOwnerThread() == current) {
			// 當(dāng)前線程為擁有鎖的線程(重復(fù)獲?。?,重入
                int c = getState() + 1;
                if (c < 0) // overflow
			// 負數(shù),state是個int類型數(shù)據(jù),超出可能導(dǎo)致溢出變?yōu)樨摂?shù)
                    throw new Error("Maximum lock count exceeded");
                setState(c);
			// 設(shè)置新的state
                return true;
            } else
			// 已有線程占鎖,返回為false
                return false;
        }

然后開始調(diào)用acquire方法,傳入1

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

調(diào)用tryAcquire()方法,其中tryAcquire()方法是一個只有拋出異常的方法,需要重寫,我們看非公平鎖的寫法

[!TIP]
這是第二次獲取鎖

        protected final boolean tryAcquire(int acquires) {
            if (getState() == 0 && !hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

這里,如果state是0,即沒有線程占用鎖的情況下getState() == 0?這個為真!hasQueuedPredecessors()執(zhí)行這個方法,這個方法會檢查是否已經(jīng)出現(xiàn)了等待隊列

    public final boolean hasQueuedPredecessors() {
        Thread first = null; Node h, s;
        if ((h = head) != null && ((s = h.next) == null ||
                                   (first = s.waiter) == null ||
                                   s.prev == null))
            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
        return first != null && first != Thread.currentThread();
    }

當(dāng)未出現(xiàn) 同步隊列/阻塞隊列 ,或者當(dāng)前線程是隊列的第一個時,執(zhí)行compareAndSetState(0, acquires),第二次嘗試獲取鎖,如果成功,返回真

否則返回假,執(zhí)行acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
			// 嘗試加入隊尾
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

Node是雙向隊列:阻塞隊列一個節(jié)點,是為了保證原子化所以包裝起來的

如果tail尾指針指向的節(jié)點不為空,則設(shè)置新生成的為尾指針指向的

否則(阻塞隊列為空),調(diào)用enq函數(shù)

    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
			// 使用CAS,防止多線程同時創(chuàng)建頭節(jié)點,所以本質(zhì)上還是需要搶入隊順序
                    tail = head;
			// 初始化頭節(jié)點,并將尾指針指向頭節(jié)點
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
			// 判斷t是否為尾節(jié)點,如果有線程更快的改掉尾節(jié)點,那么修改失敗,
			// 重新進入for循環(huán)
                    t.next = node;
                    return t;
			// 修改成功
                }
            }
        }
    }

[!TIP]
這是第三次嘗試獲取鎖

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
			// 獲取node的前一個節(jié)點,如果前一個節(jié)點是頭節(jié)點(當(dāng)前節(jié)點是第一個)
			// 執(zhí)行tryAcquire(arg),執(zhí)行第三次嘗試獲取鎖
                if (p == head && tryAcquire(arg)) {
			// 獲取鎖成功,出隊
                    setHead(node);// 將node設(shè)為頭節(jié)點
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

如果第三次嘗試獲取鎖失敗了,會調(diào)用shouldParkAfterFailedAcquire()方法,將node的前一個節(jié)點傳入(node一直都是加入的節(jié)點)

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
		// 確認前面的節(jié)點處于SIGNAL狀態(tài),即確認前面的節(jié)點會叫醒自己
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
			// Node里面僅有一個大于零的狀態(tài),即1取消狀態(tài),也就是說當(dāng)前任務(wù)被取消了
			// 持續(xù)循環(huán)值找到不再取消的節(jié)點
            pred.next = node;
        } else {
		// 將前一個節(jié)點用CAS轉(zhuǎn)為Node.SIGNAL狀態(tài)-1,返回為false
            /*
             * 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;
    }

這里插一嘴,Node節(jié)點有一些狀態(tài),來體現(xiàn)其的任務(wù)狀態(tài),如前面?zhèn)魅氲木褪仟氄缄犃校?code>addWaiter(Node.EXCLUSIVE)

    static final class Node {
        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
		// 共享隊列
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;
		// 獨占隊列
        /** waitStatus value to indicate thread has cancelled */// 取消
        static final int CANCELLED =  1;
		// 已被取消
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
		// 表示next節(jié)點已經(jīng)park,需要被喚醒
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
		// 共享狀態(tài)
        static final int PROPAGATE = -3;
if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;

如果前一個節(jié)點的waitState是0,會被CAS轉(zhuǎn)為-1,然后返回false,進而不會執(zhí)行parkAndCheckInterrupt(),繼續(xù)for的無限循環(huán),這里有可能出現(xiàn)第四次嘗試

如果前一個節(jié)點的waitState是-1,該函數(shù)返回一個true,也就可以繼續(xù)執(zhí)行parkAndCheckInterrupt()

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

當(dāng)前線程進入park狀態(tài)

至此我們完成了這個的lock過程

unlock方法#

unlock()也是公平鎖以及非公平鎖都有的方法,同樣繼承了Sync

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

Sync的release方法

    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方法

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

如果成功醒過來,該線程依然處于一種park的位置上,即parkAndCheckInterrupt這個方法上,這個方法返回是否被中斷ReentrantLock這個鎖僅獲取中斷信息,而不會做出任何操作

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

蘇醒過來之后,繼續(xù)for循環(huán),嘗試獲取鎖,失敗之后會接著park,成功就會獲取鎖,并返回中斷狀態(tài),在acquire中決定自我中斷

        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;
        }

并將setExclusiveOwnerThread傳入當(dāng)前線程,返回為真,因此在TryRelease方法里的Thread.currentThread() != getExclusiveOwnerThread()一定為假,不會拋出異常,并設(shè)置free為false,當(dāng)c也就是資源的state如果是0

			if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;

c如果是0,即沒有線程占用資源,setExclusiveOwnerThread將鎖的線程設(shè)置為空,如果不為0,也就是重入鎖僅僅解鎖一次,c依然存在多個,設(shè)置c為新的state值,然會free值(資源鎖的使用情況)

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
    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)
            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;、
		// 如果下一個節(jié)點的狀態(tài)為取消或者為空,從后向前找最后一個滿足條件的,賦值為s
        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;
        }
		// s不為空的話作為下一個被喚醒的節(jié)點,嘗試喚醒
        if (s != null)
            LockSupport.unpark(s.thread);
    }

此時,當(dāng)前節(jié)點為頭節(jié)點,調(diào)用unparkSuccessor()方法,獲取頭節(jié)點的下一個節(jié)點

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Tomcat ClassLoader打破雙親委派源碼解析

    Tomcat ClassLoader打破雙親委派源碼解析

    這篇文章主要為大家介紹了Tomcat ClassLoader打破雙親委派源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Java中LinkedHashSet的底層機制詳解

    Java中LinkedHashSet的底層機制詳解

    這篇文章主要介紹了Java中LinkedHashSet的底層機制解讀,   LinkedHashSet是具有可預(yù)知迭代順序的Set接口的哈希表和鏈接列表實現(xiàn),此實現(xiàn)與HashSet的不同之處在于,后者維護著一個運行于所有條目的雙重鏈接列表,需要的朋友可以參考下
    2023-09-09
  • Java如何計算兩個時間段內(nèi)的工作日天數(shù)

    Java如何計算兩個時間段內(nèi)的工作日天數(shù)

    這篇文章主要介紹了Java如何計算兩個時間段內(nèi)的工作日天數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • springboot的java配置方式(實例講解)

    springboot的java配置方式(實例講解)

    下面小編就為大家分享一篇實例講解springboot的java配置方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11
  • Java實現(xiàn)畫線、矩形、橢圓、字符串功能

    Java實現(xiàn)畫線、矩形、橢圓、字符串功能

    本篇文章主要介紹了Java實現(xiàn)畫線、矩形、橢圓、字符串功能的實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • MyEclipse2017創(chuàng)建Spring項目的方法

    MyEclipse2017創(chuàng)建Spring項目的方法

    這篇文章主要為大家詳細介紹了MyEclipse2017創(chuàng)建Spring項目的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 為何Java8需要引入新的日期與時間庫

    為何Java8需要引入新的日期與時間庫

    這篇文章主要給大家介紹了關(guān)于Java8為什么需要引入新的日期與時間庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java中for循環(huán)遍歷刪除操作方法

    Java中for循環(huán)遍歷刪除操作方法

    在Java中,有些場景需要遍歷集合中的元素,然后根據(jù)條件進行刪除元素的操作,本文結(jié)合示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-11-11
  • 詳解MyBatis?ResultSetHandler?結(jié)果集的解析過程

    詳解MyBatis?ResultSetHandler?結(jié)果集的解析過程

    這篇文章主要為大家介紹了MyBatis?ResultSetHandler?結(jié)果集的解析過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Java中終止線程的方法詳解

    Java中終止線程的方法詳解

    這篇文章主要介紹了Java中終止線程的方法詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評論

肇东市| 宜良县| 抚顺县| 于田县| 乌兰察布市| 托克逊县| 诸城市| 文水县| 明溪县| 广州市| 砚山县| 牟定县| 河曲县| 静乐县| 沭阳县| 海林市| 辽宁省| 甘南县| 柏乡县| 隆化县| 孟村| 调兵山市| 石台县| 绍兴县| 玉田县| 西宁市| 高州市| 汪清县| 探索| 大埔县| 南昌市| 台东市| 保靖县| 遂昌县| 北辰区| 察雅县| 福州市| 积石山| 全椒县| 类乌齐县| 修武县|