1. 程式人生 > >死磕 java同步系列之AQS終篇(面試)

死磕 java同步系列之AQS終篇(面試)

問題

(1)AQS的定位?

(2)AQS的重要組成部分?

(3)AQS運用的設計模式?

(4)AQS的總體流程?

簡介

AQS的全稱是AbstractQueuedSynchronizer,它的定位是為Java中幾乎所有的鎖和同步器提供一個基礎框架。

在之前的章節中,我們一起學習了ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch的原始碼,今天我們一起來對AQS做個總結。

狀態變數state

AQS中定義了一個狀態變數state,它有以下兩種使用方法:

(1)互斥鎖

當AQS只實現為互斥鎖的時候,每次只要原子更新state的值從0變為1成功了就獲取了鎖,可重入是通過不斷把state原子更新加1實現的。

(2)互斥鎖 + 共享鎖

當AQS需要同時實現為互斥鎖+共享鎖的時候,低16位儲存互斥鎖的狀態,高16位儲存共享鎖的狀態,主要用於實現讀寫鎖。

互斥鎖是一種獨佔鎖,每次只允許一個執行緒獨佔,且當一個執行緒獨佔時,其它執行緒將無法再獲取互斥鎖及共享鎖,但是它自己可以獲取共享鎖。

共享鎖同時允許多個執行緒佔有,只要有一個執行緒佔有了共享鎖,所有執行緒(包括自己)都將無法再獲取互斥鎖,但是可以獲取共享鎖。

AQS佇列

AQS中維護了一個佇列,獲取鎖失敗(非tryLock())的執行緒都將進入這個佇列中排隊,等待鎖釋放後喚醒下一個排隊的執行緒(互斥鎖模式下)。

Condition佇列

AQS中還有另一個非常重要的內部類ConditionObject,它實現了Condition介面,主要用於實現條件鎖。

ConditionObject中也維護了一個佇列,這個佇列主要用於等待條件的成立,當條件成立時,其它執行緒將signal這個佇列中的元素,將其移動到AQS的佇列中,等待佔有鎖的執行緒釋放鎖後被喚醒。

Condition典型的運用場景是在BlockingQueue中的實現,當佇列為空時,獲取元素的執行緒阻塞在notEmpty條件上,一旦佇列中添加了一個元素,將通知notEmpty條件,將其佇列中的元素移動到AQS佇列中等待被喚醒。

模板方法

AQS這個抽象類把模板方法設計模式運用地爐火純青,它裡面定義了一系列的模板方法,比如下面這些:

// 獲取互斥鎖
public final void acquire(int arg) {
    // tryAcquire(arg)需要子類實現
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
// 獲取互斥鎖可中斷
public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    // tryAcquire(arg)需要子類實現
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg);
}    
// 獲取共享鎖
public final void acquireShared(int arg) {
    // tryAcquireShared(arg)需要子類實現
    if (tryAcquireShared(arg) < 0)
     doAcquireShared(arg);
}
// 獲取共享鎖可中斷
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    // tryAcquireShared(arg)需要子類實現
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
// 釋放互斥鎖
public final boolean release(int arg) {
    // tryRelease(arg)需要子類實現
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
// 釋放共享鎖
public final boolean releaseShared(int arg) {
    // tryReleaseShared(arg)需要子類實現
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

獲取鎖、釋放鎖的這些方法基本上都穿插在ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch的原始碼解析中了,現在看他們是不是舒服多了,如果一開始就看這些原始碼,難免會很暈。

需要子類實現的方法

上面一起學習了AQS中幾個重要的模板方法,下面我們再一起學習下幾個需要子類實現的方法:

// 互斥模式下使用:嘗試獲取鎖
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}
// 互斥模式下使用:嘗試釋放鎖
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}
// 共享模式下使用:嘗試獲取鎖
protected int tryAcquireShared(int arg) {
    throw new UnsupportedOperationException();
}
// 共享模式下使用:嘗試釋放鎖
protected boolean tryReleaseShared(int arg) {
    throw new UnsupportedOperationException();
}
// 如果當前執行緒獨佔著鎖,返回true
protected boolean isHeldExclusively() {
    throw new UnsupportedOperationException();
}

這幾個方法為什麼不直接定義成抽象方法呢?

因為子類只要實現這幾個方法中的一部分就可以實現一個同步器了,所以不需要定義成抽象方法。

總結

今天我們大概講了下AQS中幾個重要的組成部分,搞明白了這幾個結構,AQS對你將沒有任何祕密可言,當然面試的時候能把這幾個點答清楚,面試官也會眼前一亮的。

(1)狀態變數state;

(2)AQS佇列;

(3)Condition佇列;

(4)模板方法;

(5)需要子類實現的方法;

彩蛋

經過前面的學習,您能簡要描述一下AQS獲取互斥鎖的大體流程嗎?

這裡彤哥就不作答了,相信學習完前面的內容,答這道題不是個問題了,答不上來的還需要把下面的推薦閱讀好好多看幾遍^^

推薦閱讀

1、 死磕 java同步系列之開篇

2、 死磕 java魔法類之Unsafe解析

3、 死磕 java同步系列之JMM(Java Memory Model)

4、 死磕 java同步系列之volatile解析

5、 死磕 java同步系列之synchronized解析

6、 死磕 java同步系列之自己動手寫一個鎖Lock

7、 死磕 java同步系列之AQS起篇

8、 死磕 java同步系列之ReentrantLock原始碼解析(一)——公平鎖、非公平鎖

9、 死磕 java同步系列之ReentrantLock原始碼解析(二)——條件鎖

10、 死磕 java同步系列之ReentrantLock VS synchronized

11、 死磕 java同步系列之ReentrantReadWriteLock原始碼解析

12、 死磕 java同步系列之Semaphore原始碼解析

13、 死磕 java同步系列之CountDownLatch原始碼解析

歡迎關注我的公眾號“彤哥讀原始碼”,檢視更多原始碼系列文章, 與彤哥一起暢遊原始碼的海洋。

相關推薦

java同步系列AQS面試

問題 (1)AQS的定位? (2)AQS的重要組成部分? (3)AQS運用的設計模式? (4)AQS的總體流程? 簡介 AQS的全稱是AbstractQueuedSynchronizer,它的定位是為Java中幾乎所有的鎖和同步器提供一個基礎框架。 在之前的章節中,我們一起學習了ReentrantLock、R

java同步系列AQS

問題 (1)AQS是什麼? (2)AQS的定位? (3)AQS的實現原理? (4)基於AQS實現自己的鎖? 簡介 AQS的全稱是AbstractQueuedSynchronizer,它的定位是為Java中幾乎所有的鎖和同步器提供一個基礎框架。 AQS是基於FIFO的佇列實現的,並且內部維護了一個狀態變數sta

java同步系列ReentrantLock原始碼解析——公平鎖、非公平鎖

問題 (1)重入鎖是什麼? (2)ReentrantLock如何實現重入鎖? (3)ReentrantLock為什麼預設是非公平模式? (4)ReentrantLock除了可重入還有哪些特性? 簡介 Reentrant = Re + entrant,Re是重複、又、再的意思,entrant是enter的名詞或

java同步系列ReentrantLock原始碼解析——條件鎖

問題 (1)條件鎖是什麼? (2)條件鎖適用於什麼場景? (3)條件鎖的await()是在其它執行緒signal()的時候喚醒的嗎? 簡介 條件鎖,是指在獲取鎖之後發現當前業務場景自己無法處理,而需要等待某個條件的出現才可以繼續處理時使用的一種鎖。 比如,在阻塞佇列中,當佇列中沒有元素的時候是無法彈出一個元素

java同步系列開篇

討論 關註 使用 避免死鎖 更新數據 讀寫 上下文切換 monit 缺點 簡介 同步系列,這是彤哥想了好久的名字,本來是準備寫鎖相關的內容,但是java中的CountDownLatch、Semaphore、CyclicBarrier這些類又不屬於鎖,它們和鎖又有很多共同點,

java同步系列JMMJava Memory Model

簡介 Java記憶體模型是在硬體記憶體模型上的更高層的抽象,它遮蔽了各種硬體和作業系統訪問的差異性,保證了Java程式在各種平臺下對記憶體的訪問都能達到一致的效果。 硬體記憶體模型 在正式講解Java的記憶體模型之前,我們有必要先了解一下硬體層面的一些東西。 在現代計算機的硬體體系中,CPU的運算速度是非常快

java同步系列volatile解析

問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實現原理? (4)volatile的缺陷? 簡介 volatile可以說是Java虛擬機器提供的最輕量級的同步機制了,但是它並不容易被正確地理解,以至於很多人不習慣使用它,遇到多執行緒問題一律

java同步系列synchronized解析

問題 (1)synchronized的特性? (2)synchronized的實現原理? (3)synchronized是否可重入? (4)synchronized是否是公平鎖? (5)synchronized的優化? (6)synchronized的五種使用方式? 簡介 synchronized關鍵字是Ja

java同步系列自己動手寫一個鎖Lock

問題 (1)自己動手寫一個鎖需要哪些知識? (2)自己動手寫一個鎖到底有多簡單? (3)自己能不能寫出來一個完美的鎖? 簡介 本篇文章的目標一是自己動手寫一個鎖,這個鎖的功能很簡單,能進行正常的加鎖、解鎖操作。 本篇文章的目標二是通過自己動手寫一個鎖,能更好地理解後面章節將要學習的AQS及各種同步器實現的原理

java同步系列ReentrantLock VS synchronized——結果可能跟你想的不一樣

問題 (1)ReentrantLock有哪些優點? (2)ReentrantLock有哪些缺點? (3)ReentrantLock

java同步系列ReentrantReadWriteLock原始碼解析

問題 (1)讀寫鎖是什麼? (2)讀寫鎖具有哪些特性? (3)ReentrantReadWriteLock是怎麼實現讀寫鎖的? (4)如何使用ReentrantReadWriteLock實現高效安全的TreeMap? 簡介 讀寫鎖是一種特殊的鎖,它把對共享資源的訪問分為讀訪問和寫訪問,多個執行緒可以同時對共享

java同步系列Semaphore原始碼解析

問題 (1)Semaphore是什麼? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什麼場景中? (

java同步系列StampedLock原始碼解析

問題 (1)StampedLock是什麼? (2)StampedLock具有什麼特性? (3)StampedLock是否支援可重入

java同步系列CyclicBarrier原始碼解析——有圖有真相

問題 (1)CyclicBarrier是什麼? (2)CyclicBarrier具有什麼特性? (3)CyclicBarrier與

java同步系列Phaser原始碼解析

問題 (1)Phaser是什麼? (2)Phaser具有哪些特性? (3)Phaser相對於CyclicBarrier和Count

java同步系列mysql分散式鎖

問題 (1)什麼是分散式鎖? (2)為什麼需要分散式鎖? (3)mysql如何實現分散式鎖? (4)mysql分散式鎖的優點和缺點? 簡介 隨著併發量的不斷增加,單機的服務遲早要向多節點或者微服務進化,這時候原來單機模式下使用的synchronized或者ReentrantLock將不再適用,我們迫切地需要一

java同步系列zookeeper分散式鎖

(2)zookeeper分散式鎖有哪些優點? (3)zookeeper分散式鎖有哪些缺點? 簡介 zooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,它可以為分散式應用提供一致性服務,它是Hadoop和Hbase的重要元件,同時也可以作為配置中心、註冊中心運用在微服務體系中。 本章我們將介

java同步系列redis分散式鎖進化史

(2)redis分散式鎖有哪些優點? (3)redis分散式鎖有哪些缺點? (4)redis實現分散式鎖有沒有現成的輪子可以使用? 簡介 Redis(全稱:Remote Dictionary Server 遠端字典服務)是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-

java同步系列終結

腦圖 下面是關於同步系列的一份腦圖,列舉了主要的知識點和問題點,看過本系列文章的同學可以根據腦圖自行回顧所學的內容,也可以作為面試前的準備。 如果有需要高清無碼原圖的同學,可以關注公眾號“彤哥讀原始碼”,回覆“sync”領取。 總結 所謂同步,就是保證多執行緒(包括多程序)對共享資源的讀寫能夠安全有效的執