1. 程式人生 > 程式設計 >ReentrantLock-基於AQS實現獨佔鎖

ReentrantLock-基於AQS實現獨佔鎖

1 概述

ReentrantLock是基於AQS實現的一款獨佔鎖,有公平鎖和非公平鎖兩種模式。

預設是使用的非公平鎖:

    public ReentrantLock() {
        sync = new NonfairSync();
    }
複製程式碼

也可指定模式:

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
複製程式碼
  • 1 ReentrantLock實現了Lock介面;
  • 2 ReentrantLock定義了內部類Sync
    繼承AQS:abstract static class Sync extends AbstractQueuedSynchronizer{....}
  • 3 Sync是一個抽象類,有兩個實現類NonfairSync/FairSync,分別用來實現非公平鎖/公平鎖

官方示例:

class X {
    private final ReentrantLock lock = new ReentrantLock();
    // ...
 
    public void m() {
      lock.lock();  // block until condition holds
      try {
        // ... method body
} finally { lock.unlock() } } } 複製程式碼

2 實現

本文僅從ReentrantLock的lock/unlock的實現,分析如何基於AQS實現一個獨佔鎖。

根據AQS約定(可參考AQS原始碼分析及核心方法解析):

  • 1 lock:實現tryAcquire,並在lock時呼叫acquire
  • 2 unlock:實現tryRelease,並在unlock時呼叫release

2 lock()

ReentrantLock.lock()呼叫了Sync.lock(),而Sync.lock()是一個抽象方法,由子類實現。

所以NonfairSync/FairSync兩個類中,必然使用了acquire方法去獲取鎖,並實現了tryAcquire方法。

2.1 NonfairSync

2.1.1 lock

  • 1 呼叫compareAndSetState將state值由0置換為1,成功的話,說明當前沒有其他執行緒持有鎖,不去排隊,直接持有。通過setExclusiveOwnerThread將當前執行緒設定為獨佔鎖持有者。
  • 2 否則通過acquire去排隊。
        final void lock() {
            if (compareAndSetState(0,1)) // 如果當前state==0,則說明沒有其他執行緒持有鎖,CAS成功。
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
複製程式碼

2.1.2 tryAcquire

NonfairSync.tryAcquire直接呼叫的Sync.nonfairTryAcquire

nonfairTryAcquire是非公平的tryAcquire實現方式,不會通過AQS.hasQueuedPredecessors來判斷是有執行緒在排隊。

        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                // state == 0,說明沒有其他執行緒持有鎖。
                if (compareAndSetState(0,acquires)) {
                    // 將當前執行緒設定為`獨佔鎖持有者`,tryAcqire成功。
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果當前執行緒正是`獨佔鎖持有者`,疊加state,實現`可重入`,tryAcqire成功。
                也就是說AQS的同步列表中,有多個當前執行緒的節點。
                */
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
複製程式碼

2.2 FairSync

2.2.1 lock

沒有做compareAndSetState嘗試,直接將自己加入AQS的同步佇列中。

        final void lock() {
            acquire(1);
        }
複製程式碼

2.2.2 tryAcquire

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {  // state == 0,說明沒有其他執行緒持有鎖。
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0,acquires)) {
                    /*
                    `!hasQueuedPredecessors()` 說明AQS的同步佇列中,沒有比自己更優先的執行緒在等待
                    */
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                /* 
                如果當前執行緒正是`獨佔鎖持有者`,疊加state,實現`可重入`,tryAcqire成功。
                也就是說AQS的同步列表中,有多個當前執行緒的節點。
                */
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
複製程式碼

FairSync.tryAcquireNonFairSync.tryAcquire多了一個!hasQueuedPredecessors()的判斷,其他流程都是一樣的。

3 unlock()

unlock操作,NonFairSync/FairSync中沒有區分,直接在Sync中實現。

Sync中的unlock呼叫了AQS.release,並實現了tryRelease

public void unlock() {
        sync.release(1);
    }
複製程式碼

3.1 tryRelease

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            
            // 當前執行緒不是`獨佔鎖持有者`,丟擲異常。
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) { // c == 0 說明鎖已經完全釋放。
                free = true;
                // 將當前`獨佔鎖持有者`置空。
                setExclusiveOwnerThread(null);
            }
            // 更新state值
            setState(c);
            return free;
        }
複製程式碼

4 總結

NonFairSync/FairSync基本流程是一樣的,不同的是:

  • 1 NonFairSync在lock時,會先嚐試compareAndSetState(0,1)搶佔鎖,失敗的話再進行acquire(1)FairSync直接進行acquire(1)排隊。
  • 2 FairSynctryAcquire時,在判斷compareAndSetState(0,acquires)的同時,多進行了一個hasQueuedPredecessors()的判斷,用於判斷同步佇列中是否有比自己優先的執行緒。