ReentrantLock的實現原理

ReentrantLock是一個顯示鎖,實現基礎都是AQS。所謂的AQS就是AbstractQueuedSynchronizer,

AQS的作用

  • 用來構建鎖和同步工具的框架, ReentrantLock、CountDownLatch、Semaphore基礎都是AQS
  • AQS有個state變量,是int類型,使用了volatile修飾,AQS圍繞state提供兩種基本的獲取和釋放功能

ReentrantLock分析

  • 在ReentrantLock中定義了一個抽象的靜態類Sync,該類繼承了AbstractQueuedSynchronizer
  • ReentrantLock中還定義了公平鎖和非公平鎖(FairSync/NonfairSync),這兩個鎖繼承了Sync。
    • 公平鎖:線程獲取鎖的順序和調用lock的順序一樣,FIFO先進先出
    • 非公平鎖:線程鎖獲取所得順序和調用lock的順序無關,隨機的
  • ReentrantLock默認是實現非公平鎖

非公平鎖

/**
  * 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();
    }
  • 如何獲取鎖獲取鎖
    • ReentrantLock提供lock()方法,該方法直接使用的是Sync類中的lock方法,該方法是個抽象方法,因爲ReentrantLock默認是非公平鎖,所以lock()方法的具體實現在NonfairSync中的lock()中
final void lock() {
	//判斷當前state是否是0,如果是0,則將值設爲1,並將當前線程設爲獨佔鎖線程
	//否則
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
    	//如果當前state不是0,則當前線程放入等待隊列
        acquire(1);
}

//調用AbstractQueuedSynchronized類中的acquire()來中斷
public final void acquire(int arg) {
  //調用NonfairSync非公平鎖類的tryAcquire()方法
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

//使用addWaiter()方法創建一個Node,同時給一個類型
//將線程加入阻塞隊列
//Node.EXCLUSIVE for exclusive, Node.SHARED for shared
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Tail of the wait queue, lazily initialized.  Modified only via method enq to add new wait node.
    // tail是等待隊列的尾部,延遲初始化,通過enq()方法添加節點
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //enq方法是一個死循環(是爲了保證Node一定能插入隊列),當隊列爲空時,會創建一個空的Node作爲head節點
    enq(node);
    return node;
}

//不間斷的獲取已經在隊列中的獨佔線程
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);
        }
    }

shouldParkAfterFailedAcquire(Node pred, Node node)該方法的作用是檢查和更新獲取失敗的節點的狀態。如果線程要阻塞就返回true

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            //如果前一個節點的狀態是SIGNAL,阻塞,返回true
            return true;
        if (ws > 0) {
          // 如果前一個節點的狀態是CANCELLED,則跳過所有前置任務(通過循環將前面的節點都移除)
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
     		//如果是其他狀態,則都將狀態更新爲SIGNAL
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
final boolean nonfairTryAcquire(int acquires) {
	//獲取當前線程
    final Thread current = Thread.currentThread();
    //獲得AQS的state是否等於0,等於0表示沒有人佔有
     int c = getState();
     if (c == 0) {
     	// 然後比較並更新state,如果state是0,就把值設爲1
         if (compareAndSetState(0, acquires)) {
         // 當前線程獲取鎖,並設置線程擁有獨佔訪問權,即獲得獨佔鎖
             setExclusiveOwnerThread(current);
             return true;
         }
     }
     //判斷當前線程是否是獨佔鎖線程,因爲ReentrantLock是可重入的,線程可以不停的lock來增加state的值,對應的就需要unlock來解鎖,直到state爲0
     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;
}
  • 鎖的釋放
    • ReentrantLock提供了unlock()方法,該方法中調用了Sync中的release方法。sync.release(1);入參寫死爲1,因爲每當一個線程獲取到獨佔線程時,都會把自己設爲head.
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章