源碼分析之 ReentrantLock

ReentrantLock類是屬於java.util.concurrent的。實現了Lock, java.io.Serializable兩個接口,是一個可重入的互斥鎖,所謂可重入是線程能夠重複獲取已經持有的鎖。java

/**
    * Creates an instance of {@code ReentrantLock}.
    * This is equivalent to using {@code ReentrantLock(false)}.
    */
   public ReentrantLock() {
       sync = new NonfairSync();
   }
   /**
    * Creates an instance of {@code ReentrantLock} with the
    * given fairness policy.
    *
    * @param fair {@code true} if this lock should use a fair ordering policy
    */
   public ReentrantLock(boolean fair) {
       sync = fair ? new FairSync() : new NonfairSync();
   }
abstract static class Sync extends AbstractQueuedSynchronizer

ReentrantLock實現鎖的機制是經過Sync進行操做的。Sync類是繼承AbstractQueuedSynchronizer類的。這也就代表ReentrantLock是基於AQS的實現的。‘node

Sync,FairSyncNonFairSync都是ReentrantLock的靜態內部類。FairSyncNonFairSync又是Sync具體實現類,分別對應的是公平鎖和非公平鎖,公平主要是指按照FIFO原則順序獲取鎖,非公平能夠根據定義的規則來選擇得到鎖。less

NonFairSync 源碼分析

非公平鎖NonFairSyncReentrantLock默認的實現方式。這裏能夠看一下它的lock實現過程:源碼分析

/**
 * Performs lock.  Try immediate barge, backing up to normal
 * acquire on failure.
 */
final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}
  • 首先經過CAS更新state狀態,若是更新成功,則獲取鎖,設定當前線程爲鎖的擁有者。
protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
  • 若是更新失敗,代表當前鎖被其餘線程佔有。則會調用acquire(1)方法。acquire具體實現以下:
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }

tryAcquire過程,將再次嘗試獲取鎖,其中tryAcquire在靜態內部類NonfairSync類中被重寫,具體的實現是SyncnonfairTryAcquire方法:ui

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

其主要過程是先獲取state的值,若是等於0,則經過CAS更新state的值。若是state不爲0,則判斷當前線程是不是鎖的持有者,若是是,則將state加1,返回truethis

若是tryAcquire仍然失敗的話,首先會調用addWaiter(Node.EXCLUSIVE),將當前線程加入到等待隊列的尾部。而後會調用acquireQueued方法,acquireQueued的做用主要是用來阻塞線程的:spa

/**
 * Acquires in exclusive uninterruptible mode for thread already in
 * queue. Used by condition wait methods as well as acquire.
 *
 * @param node the node
 * @param arg the acquire argument
 * @return {@code true} if interrupted while waiting
 */
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

這裏是一個循環自旋操做,在阻塞線程以前,首先判斷線程自身前面的節點是不是head節點,若是是,則從新去獲取鎖,獲取成功後,返回,並取消不斷獲取的過程。若是不是,調用shouldParkAfterFailedAcquire方法去判斷是否應該阻塞當前線程,主要是經過節點的waitStatus來進行判斷。線程

FairSync 源碼分析

公平鎖FairSync和非公平鎖NonFairSync的實現很類似,這裏比較一下二者的差異。code

  • FairSynclock方法中沒有像NonFairSync中先去經過CAS操做state去獲取鎖,而是直接經過tryAcquire去獲取鎖。
final void lock() {
    acquire(1);
}
  • FairSync版本tryAcquire在獲取鎖的過程當中,須要先判斷隊列中是否有其餘等待的線程,若是沒有,纔回去嘗試獲取鎖。
/**
 * Fair version of tryAcquire.  Don't grant access unless
 * recursive call or no waiters or is first.
 */
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        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;
}

unlock() 釋放鎖

釋放鎖沒有區分公平和非公平的。主要的工做就是減少state的值。當state等0的時候,釋放鎖並喚醒隊裏中其餘線程來獲取鎖。orm

public void unlock() {
    sync.release(1);
}
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        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;
}

總結

  • ReentrantLock是經過AQSstate字段來判斷所是否被佔用。
  • 公平非公平的差異是在於獲取鎖的方式是不是按照順序的。
  • state操做是經過CAS實現的。經過隊列來實現因搶佔鎖被阻塞的隊列。
  • 在阻塞線程的過程當中,AQS有自旋的過程,並不是是獲取不到鎖就直接阻塞。
相關文章
相關標籤/搜索