【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)

WriteOnRead發表於2019-08-04

概述

 

前文「JDK原始碼分析-Lock&Condition」簡要分析了 Lock 介面,它在 JDK 中的實現類主要是 ReentrantLock (可譯為“重入鎖”)。ReentrantLock 的實現主要依賴於其內部的一個巢狀類 Sync,而 Sync 又繼承自 AbstractQueuedSynchronizer (簡稱 AQS)。而且,不僅 ReentrantLock,其他一些併發工具類如 CountdownLatch、CyclicBarrier 等,其實現也都是基於 AQS 類。AQS 可以理解為併發包中許多類實現的基石。因此,在分析併發包中常用類的實現原理前,有必要先理解一下 AQS,之後再分析的時候就會簡單不少。

 

AQS 內部有一個核心變數 state;此外,以 Node 類為節點維護了兩種佇列:主佇列(main queue)和條件佇列(condition queue),簡單起見,分別可以將二者理解為雙連結串列和單連結串列。

 

AQS 就像是提供了一套基礎設施的裝置,其它常用類如 ReentrantLock、CountdownLatch 等的內部巢狀類 Sync,都是在 AQS 提供的基礎設施之上制定了自己的“遊戲規則”,進而生產出了不同的產品。而它們的遊戲規則都是圍繞 state 變數和這兩種佇列進行操作的。

 

PS: 由於 AQS 內容較多,因此打算分多篇文章進行分析,本文先對其整體進行概述。

 

程式碼分析

 

AQS 類簽名:

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {}
可以看到它是一個抽象類,不能直接被例項化。它的父類 AbstractOwnableSynchronizer 的主要程式碼如下:
public abstract class AbstractOwnableSynchronizer
    implements java.io.Serializable {

    /**
     * The current owner of exclusive mode synchronization.
     */
    private transient Thread exclusiveOwnerThread;
    
    // 其他程式碼
}

其內部主要維護了一個變數 exclusiveOwnerThread,作用是標記獨佔模式下的 Owner 執行緒,後面涉及到的時候再進行分析。

 

巢狀類

 

AQS 內部有兩個巢狀類,分別為 Node 和 ConditionObject。

Node 類程式碼如下:

static final class Node {
    // 共享模式
    static final Node SHARED = new Node();
    // 獨佔模式
    static final Node EXCLUSIVE = null;
    
    // waitStatus的幾種狀態
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;
    volatile int waitStatus;

    // 前驅節點(主佇列)
    volatile Node prev;
    // 後繼節點(主佇列)
    volatile Node next;
    // 節點的執行緒
    volatile Thread thread;
    // 後繼節點(條件佇列)
    Node nextWaiter;

    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    Node() {    // Used to establish initial head or SHARED marker
    }
    Node(Thread thread, Node mode) {     // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }

    Node(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

新增到主佇列用的是第二個構造器,Node 類可以理解為對執行緒 Thread 的封裝。因此,在主佇列中排隊的一個個節點可以理解為一個個有模式(mode)、有狀態(waitStatus)的執行緒。

 

巢狀類 ConditionObject:

public class ConditionObject implements Condition, java.io.Serializable {
    /** First node of condition queue. */
    private transient Node firstWaiter;
    
    /** Last node of condition queue. */
    private transient Node lastWaiter;
    // ...
}

ConditionObject 實現了 Condition 介面,它主要操作的是條件佇列,這裡只貼了其類簽名和頭尾節點,後面用到的時候再具體分析。

 

主要變數

 

AQS 程式碼雖長,但它的成員變數卻不多,如下:

// 主佇列頭節點
private transient volatile Node head;

// 主佇列尾結點
private transient volatile Node tail;

// 狀態,AQS 維護的一個核心變數
private volatile int state;

其中,head 和 tail 為主佇列的頭尾節點,state 為 AQS 維護的核心變數,ReentrantLock 等類中的 Sync 類實現,都是通過操作 state 來實現各自功能的。

 

CAS 操作

 

AQS 內部通過 Unsafe 類實現了一系列 CAS (Compare And Swap) 操作(有關 CAS 的概念這裡不再詳解,可自行搜尋瞭解):

// 獲取 Unsafe 例項
private static final Unsafe unsafe = Unsafe.getUnsafe();
// state、head、tail 等變數的記憶體偏移地址
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;
static {
    try {
        stateOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));
    } catch (Exception ex) { throw new Error(ex); }
}

// 一些 CAS 操作
private final boolean compareAndSetHead(Node update) {
    return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

private final boolean compareAndSetTail(Node expect, Node update) {
    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}

private static final boolean compareAndSetWaitStatus(Node node,
                                                     int expect,
                                                     int update) {
    return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                    expect, update);
}

private static final boolean compareAndSetNext(Node node,
                                               Node expect,
                                               Node update) {
    return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}

AQS 內部的許多操作是通過 CAS 來實現執行緒安全的。

 

小結

 

1. AQS 是一個抽象類,無法直接進行例項化;

2. AQS 內部維護了一個核心變數 state,以及兩種佇列:主佇列(main queue)和條件佇列(condition queue);

3. AQS 提供了一套基礎設施,ReentrantLock 等類通常用一個內部巢狀類 Sync 繼承 AQS,並在 Sync 類中制定自己的“遊戲規則”。

 

本文僅對 AQS 做了概述,後面再詳細分析實現原理。此外,還有一個類 AbstractQueuedLongSynchronizer,它與 AQS 基本完全一樣,區別在於前者的 state 變數為 long 型別,而 AQS 為 int 型別,不再單獨進行分析。

 

PS: 有幾篇文章寫得也不錯,連結如下:

https://www.cnblogs.com/liuyun1995/p/8400663.html

 

 

Stay hungry, stay foolish.

PS: 本文首發於微信公眾號【WriteOnRead】。

相關文章