成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:說下你對AQS的理解!

開發 前端
AQS,是?AbstractQueuedSynchronizer(抽象隊列同步器)這個類的簡稱,也是 Java JUC 包中的靈魂,ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、CyclicBarrier 都是通過其實現鎖或同步器的。

在技術面試的時候,“說下你對 AQS 的理解”,這個問題出現的概率屬實不低,而一些技術底子一般的同學,又非常容易被它復雜的底層源碼弄得暈頭轉向。

今天這篇文章,我們就以做減法的方式,將這個知識點徹底地大家講清楚。

AQS,是 AbstractQueuedSynchronizer(抽象隊列同步器)這個類的簡稱,也是 Java JUC 包中的靈魂,ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch、CyclicBarrier 都是通過其實現鎖或同步器的。

其核心思想為,在多線程并發訪問共享資源時,通過雙向鏈表實現的先進先出 CLH 隊列進行線程排隊,并通過由 volatile 修飾的 state 變量來標識資源的鎖占用狀態。

如下圖所示:

圖片圖片

在 AQS 中提供了兩種資源獲取方式:

獨占模式(Exclusive),在同一時刻只能有一個線程獲取競態資源,比如:ReentrantLock。

共享模式(Share),在同一時刻可以有多個(參數設定)線程獲取競態資源,比如:CountDownLatch、Semaphore。

AQS 方法詳述

AQS 的方法大致分為三類,分別是獨占模式下的方法、共享模式下的方法、通過模板方法模式留給子類實現的方法。

獨占模式:

// 獲取鎖
public final void acquire(int arg) 
// 以可中斷的方式獲取鎖
public final void acquireInterruptibly(int arg)
// 以帶超時時間的方式,嘗試獲取鎖
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
// 釋放鎖
public final boolean release(int arg)

共享模式:

// 獲取鎖
public final void acquireShared(int arg)
// 以可中斷的方式獲取鎖
public final void acquireSharedInterruptibly(int arg)
// 以帶超時時間的方式,嘗試獲取鎖
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
// 釋放鎖
public final boolean releaseShared(int arg)

需要子類實現的方法:

// 嘗試獲取獨占鎖
protected boolean tryAcquire(int arg);
// 嘗試釋放獨占鎖
protected boolean tryRelease(int arg);
// 嘗試獲取共享鎖
protected int tryAcquireShared(int arg);
// 嘗試釋放共享鎖
protected boolean tryReleaseShared(int arg);
// 判斷當前線程是否正在持有鎖
protected boolean isHeldExclusively();

看到 AQS 父類實現了一部分方法,也預留了一些方法讓 ReentrantLock、CountDownLatch、Semaphore、CyclicBarrier 等子類實現,我們想到了哪種設計模式?

是的,模板方法模式。

模板方法模式:定義一個操作中算法的框架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個算法的結構,即可重定義該算法的某些步驟。

使用模板方法模式,可以將一個操作的復雜流程的實現步驟進行拆分,封裝在一系列基本方法中,在抽象父類提供一個模板方法來定義整體執行步驟,而通過其子類來覆蓋某個步驟,從而使得相同的執行步驟可以有不同的執行結果。

類結構如下:

圖片圖片

模板方法模式的優點在于:

  • 代碼復用性高,父類的模板方法和具體方法都可以供多個子類復用。
  • 代碼靈活性高,可根據業務迭代情況,靈活選擇哪部分復用父類具體方法,哪部分進行子類覆蓋實現。

嗯,這些底層源碼的設計還是非常巧妙的,而設計模式本身也并不是有些人口中的過度設計的“花架子”。

ReentrantLock 與 AQS 

接下來我們看下,ReentrantLock 是如何通過 AQS 來實現鎖機制的。

兩者間的 UML 圖如下所示:

圖片圖片

從圖中可以看到,ReentrantLock 中有一個 Sync 內部類,Sync 繼承自 AQS,且 Sync 有兩個子類 FairSync 和 NonfairSync,分別用于實現公平鎖和非公平鎖。

我們梳理一下源碼,看看 ReentrantLock 如何實現非公平鎖的。

代碼入口如下,我們看只有兩個方法加上一個判斷。

public class ReentrantLock implements Lock, java.io.Serializable{


    abstract static class Sync extends AbstractQueuedSynchronizer {
        final void lock() {    
            if (!initialTryLock())
                acquire(1);
            }
        }
    }     
}

來看下該方法的具體實現,簡而言之,該方法嘗試以獨占的方式獲取鎖。

static final class NonfairSync extends Sync {    
    final boolean initialTryLock() {        
        Thread current = Thread.currentThread();        
        if (compareAndSetState(0, 1)) {
            // first attempt is unguarded            
            setExclusiveOwnerThread(current);            
            return true;        
        } else if (getExclusiveOwnerThread() == current) {
            int c = getState() + 1;            
            if (c < 0) // overflow                
                throw new Error("Maximum lock count exceeded");      
            setState(c);            
            return true;        
        } else            
            return false;   
     }
 }

先是通過 compareAndSetState(0, 1) 方法,以原子操作的方式將 AQS 類中的 state 變量值從 0 修改到 1。

我們在上文中提到過,state 變量來標識資源的鎖占用狀態,0 代表未占用,1 代表已占用,大于 1 則代表鎖被重入,那么該操作就是嘗試獲取鎖。

若該操作執行成功,則通過 setExclusiveOwnerThread(current) 作用是將當前線程設置為持有獨占鎖的線程,并返回 true,代表獲取鎖成功了。

再往下分析 getExclusiveOwnerThread() == current,這是判斷當前線程是否已獲取該鎖且處于未釋放的狀態,若判斷成立則將 state 變量+1代表重入,并返回 true 表示獲取鎖成功。

btw:從這段代碼邏輯上看,知道為什么叫非公平鎖了吧,一上來并沒有通過 AQS 排隊,而且先去爭搶鎖。

接下來我們繼續來看acquire(1)方法,代碼如下:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
    public final void acquire(int arg) {
        if (!tryAcquire(arg))
            acquire(null, arg, false, false, false, 0L);
    }
}

方法體重有兩個方法加上一個判斷,先來看 tryAcquire(arg) 方法的執行邏輯。

static final class NonfairSync extends Sync {
    protected final boolean tryAcquire(int acquires) {
        if (getState() == 0 && compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
}

這塊代碼的邏輯竟然跟上面 initialTryLock() 方法的前半段幾乎一樣,先是通過 compareAndSetState(0, 1) 方法將 AQS 類中的 state 變量值從 0 修改到 1。

若該操作執行成功,則通過 setExclusiveOwnerThread(current) 作用是將當前線程設置為持有獨占鎖的線程,并返回 true,代表獲取鎖成功了。

btw:果然是非公平鎖啊,這是誓要將插隊爭搶鎖進行到底了。

下面就是 AQS 中的重頭戲了,acquire(null, arg, false, false, false, 0L)方法,實現排隊獲取鎖。

代碼實現如下:

圖片圖片

這塊代碼并非主業務鏈路,先是進行了三個判斷,當前節點不是 first 節點和 head 節點,且前驅結點不為null。

btw:head 節點可以理解為“當前持有獨占鎖的線程”,而在 head 節點之后的線程都處于阻塞、等待被喚醒的狀態,而 first 節點則是同步隊列中第一個等待獲取鎖的線程。

接下來 pred.status < 0 代表前驅節點已經被取消,結果為 true 則做一次等待隊列清理。

而 pred.prev == null 則是判斷前驅節點是否為 null,結果為 true 則跳到下一次循環中。

圖片圖片

這段代碼的意思是,在當前節點為 first 節點或前驅節點為 null (未入隊)的情況下,繼續通過 tryAcquire(arg) 方法嘗試獲取鎖。

圖片圖片

這段代碼看起來比較復雜,其實也是有邏輯性的。

1、前兩個大的邏輯分支判斷的意思是,先創建一個獨占節點,并將該節點加入到 CLH 隊列的尾部。

2、如果當前節點為 first 節點,且自旋數大于 0,則繼續嘗試自旋獲取鎖。

3、將當前節點的狀態值設置為“等待中”。

4、當前節點自旋失敗,使用 LockSupport.pack() 方法掛起線程。

5、當獨占鎖被釋放,隊列中的 first 節點的線程將被喚醒,清除當前節點的等待狀態。

責任編輯:武曉燕 來源: 托尼學長
相關推薦

2021-11-25 10:18:42

RESTfulJava互聯網

2021-08-09 07:47:40

Git面試版本

2020-12-01 08:47:36

Java異常開發

2025-02-21 15:25:54

虛擬線程輕量級

2024-09-27 15:43:52

零拷貝DMAIO

2020-06-12 15:50:56

options前端服務器

2022-03-21 09:05:18

volatileCPUJava

2025-03-21 00:00:05

Reactor設計模式I/O 機制

2024-10-24 16:14:43

數據傳輸CPU零拷貝

2024-08-27 12:36:33

2020-06-19 15:32:56

HashMap面試代碼

2024-06-13 08:01:19

2025-03-07 00:00:10

2019-07-26 06:42:28

PG架構數據庫

2024-10-12 16:25:12

2021-09-16 07:52:18

算法應用場景

2024-09-26 16:01:52

2024-08-26 14:52:58

JavaScript循環機制

2019-05-10 10:50:04

Spring AOPJDK動態代理CGLIB動態代理

2021-09-26 15:34:21

內部結構方法區
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91精品国产欧美一区二区 | 国产激情网站 | av在线伊人 | 超碰电影 | 中文字字幕一区二区三区四区五区 | 亚洲国产成人精品女人久久久 | 羞羞的视频免费观看 | 在线日韩在线 | 一区二区三区在线电影 | 一色一黄视频 | 国产精品久久久久久久久久久新郎 | 狠狠躁天天躁夜夜躁婷婷老牛影视 | 精品国产女人 | 草久久 | 亚洲精品一区久久久久久 | 最新伦理片| 黑人巨大精品欧美一区二区免费 | 区一区二区三在线观看 | 日韩在线一区二区三区 | 91久久精品日日躁夜夜躁国产 | 亚洲欧美网站 | 欧美片网站免费 | 日韩在线看片 | 国产精品国产精品 | 亚洲成人一二区 | 中文字幕一区在线 | 在线欧美亚洲 | 国产一区二区视频免费在线观看 | 亚洲国产一区二区三区 | 一区二区三区福利视频 | 欧美成人综合 | 国产精品久久毛片av大全日韩 | 美女艹b | 成人午夜精品一区二区三区 | 国产精品99久久久久 | 黄网站涩免费蜜桃网站 | 日韩精品一区二区三区中文在线 | 狠狠操狠狠| 国产一区二区久久 | 久久av一区二区三区 | 午夜男人的天堂 |