ReentrantLock閱讀

ReentrantLock

ReentrantLock是一個互斥鎖,也是一個可重入鎖。ReentrantLock鎖在同一時刻只能被一個線程持有,但是它可被單個線程多次獲取,每獲取一次AQS的state就加1。
ReentrantLock內部的實現(公平鎖和非公平鎖)都是基於內部Sync的實現。

內部結構

ReentrantLock內部定義了三個重要的內部類,Sync、FairSync、NonfairSync。

Sync繼承自抽象類AbstractQueuedSynchronizer,FairSync(公平鎖)和 NonfairSync(非公平鎖)繼承於Sync。

Sync

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = -5179523762034025860L;

    abstract void lock();
    //非公平鎖的TryAcquire
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {//沒有被任何線程持有
            if (compareAndSetState(0, acquires)) {//CAS 獲取
                setExclusiveOwnerThread(current);//獲取成功,將當前線程設置爲Owner
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {//如果當前線程已獲取鎖,將state+1返回
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }

    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;
    }
    //持有鎖的線程是否是當前線程
    protected final boolean isHeldExclusively() {
        return getExclusiveOwnerThread() == Thread.currentThread();
    }
    //newCondition
    final ConditionObject newCondition() {
        return new ConditionObject();
    }
    //持有鎖的線程
    final Thread getOwner() {
        return getState() == 0 ? null : getExclusiveOwnerThread();
    }

    final int getHoldCount() {
        return isHeldExclusively() ? getState() : 0;
    }

    final boolean isLocked() {
        return getState() != 0;
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
    }
}

Sync是ReentrantLock實現同步控制的基礎。Sync內部定義了一些方法:lock(獲取鎖的方法,在子類實現)、nonfairTryAcquire(非公平鎖的嘗試獲取資源)、tryRelease(釋放資源)。

NonfairSync

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

NonfairSync是內部非公平鎖的定義,非公平鎖獲取鎖的流程:

  1. 調用lock方法,lock方法首先會進行CAS操作,將state屬性嘗試設置爲1,如果成功,則代表獲取到鎖,將exclusiveOwnerThread屬性設置爲當前獲取鎖的線程。
  2. 如果線程CAS失敗,則調用AQS的acquire方法,去獲取鎖,tryAcquire(1)是子類自己的實現,調用了nonfairTryAcquire方法。如果調用了nonfairTryAcquire方法獲取鎖失敗,那就會吧當前線程包裝爲Node加入同步隊列。

FairSync

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }
    //tryAcquire方法的公平鎖版本,雖然是公平的,但是不保證一定會獲取鎖,除非是遞歸調用或者是第一個節點或者是前面無等待線程
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            //hasQueuedPredecessors方法判斷當先線程前面是否還有等待線程,如果有等待線程,則不去競爭獲取鎖
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

公平鎖在加鎖的時候不會先嚐試去加鎖,直接去調用AQS的acquire方法去獲取鎖,在自己定義的嘗試獲取資源中,如果state爲0,也會先去判斷當前線程前面是否還有線程等待,如果沒有等待的線程纔會自己獲取鎖,否則加入等待隊列;如果是當前線程獲取到了鎖則state+1.

公平鎖和非公平鎖的不同

  1. 公平鎖能保證:老的線程排隊使用鎖,新線程仍然排隊使用鎖。
  2. 非公平鎖保證:老的線程排隊使用鎖;但是無法保證新線程搶佔已經在排隊的線程的鎖。
發佈了196 篇原創文章 · 獲贊 18 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章