ReentrantLock

在進行ReentrantLock的源碼解析以前先了解些基本概念:html

(1)AQS:AbstractQueuedSynchronizerjava

(2)獨佔鎖:鎖在一個時間點只能被一個線程鎖佔有。根據鎖的獲取機制,它又劃分爲公平鎖和非公平鎖。公平鎖是按照經過CLH等待線程按照先來先得的規則公平的獲取鎖;而非公平鎖則當線程要獲取鎖時會無視CLH等待隊列而直接獲取鎖api

(3)共享鎖:能被多個線程同時擁有,能被共享的鎖多線程

(4)CLH隊列:CLH是一個非阻塞的FIFO隊列,AQS中管理等待鎖的線程隊列併發

(5)CAS:Compare And Swapless

 

在高併發的互聯網項目中,鎖經常用來解決資源共享的問題。ReentrantLock是可重入的互斥鎖(可重入鎖也叫遞歸鎖,當前線程外層函數得到鎖以後內層遞歸函數仍然可獲取該鎖),它具備與使用synchronized方法和語句所訪問的隱式監視器鎖相同的一些基本行爲和語義但功能更強大。函數

1.ReentrantLock的使用高併發

  private final ReentrantLock lock = new ReentrantLock();源碼分析

   // ...ui

   public void m() {

     lock.lock();  // block until condition holds

     try {

       // ... method body

     } finally {

       lock.unlock();

     }

   }

 }

2. ReentrantLock的構造函數摘要

ReentrantLock的內部維護了Sync的對象引用,Sync是重入鎖ReentrantLock的內部類,它是提供了全部實現機制的同步器。

private final Sync sync;

abstract static class Sync extends AbstractQueuedSynchronizer;

static final class NonfairSync extends Sync;

static final class FairSync extends Sync;

 (1)默認爲非公平鎖

   public ReentrantLock() {

     sync = new NonfairSync();

}

(2)建立一個具備給定公平策略的ReentrantLock

   public ReentrantLock(boolean fair) {

     sync = fair ? new FairSync() : new NonfairSync();

}

當boolean fair設置爲true時,在多個線程的爭用下這些鎖傾向於將訪問權授與等待時間最長的線程,不然此鎖將沒法保證任何特定訪問順序。使用公平鎖的程序在許多線程訪問時表現爲很低的整體吞吐量,可是在得到鎖和保證鎖分配的均衡性時差別較小。公平鎖不能保證線程調度的公平性,所以使用公平鎖的衆多線程中的一員可能得到多倍的成功機會,這種狀況發生在其餘活動線程沒有被處理而且目前並未持有鎖時。

3.ReentrantLock實現原理解析

  public void unlock() {

    sync.release(1);

}

  public void lock() {

    sync.lock();

  }

ReentrantLock的鎖的獲取與釋放都是由Sync這個類來完成的。Sync是抽象靜態內部類,它繼承抽象隊列同步器:AbstractQueuedSynchronizer。NonfairSync和FairSync獲取鎖的實現方式是不相同的。

 

NonfairSync鎖的獲取:

final void lock() {

  if (compareAndSetState(0, 1))

     setExclusiveOwnerThread(Thread.currentThread());

  else

     acquire(1);

}

acquire(1)中1是設置鎖的狀態的參數,對於獨佔鎖而言,鎖處於可獲取狀態時,它的狀態值是0;鎖被線程初次獲取到了它的狀態值就變成了1,若是屢次獲取則會依次增長數值。

FairSync鎖的獲取:

final void lock() {

   acquire(1);

}

公平鎖和非公平鎖獲取鎖的方式的不一樣在於:非公平鎖會利用CAS去判斷state值是否符合預期,若是符合預期則會更新state值,而後把當前線程賦值給exclusiveOwnerThread,若是不符合預期就直接調用acquire(1)獲取鎖。公平鎖和非公平鎖的acquire實現方法是相同的,可是其內部tryAcquire實現方法存在差別。

 

獲取鎖相關源碼解析:

* Atomically sets synchronization state to the given updated value if the current * state value equals the expected value.This operation has memory semantics of

* a volatile read and write

protected final boolean compareAndSetState(int expect, int update) {

   return unsafe.compareAndSwapInt(this, stateOffset, expect, update);

}

Note:compareAndSetState是AbstractQueuedSynchronizer的方法,stateOffset是指抽象隊列同步器的成員變量state(private volatile int state)的內存偏移地址。由以上源碼解析可得知compareAndSwapInt()是sun.misc.Unsafe類中的一個本地方法,它以原子的方式操做當前線程;若當前線程的狀態爲expect,則設置它的狀態爲update。

 

* Sets the thread that currently owns exclusive access. A null argument indicates * that no thread owns access.This method does not otherwise impose(利用) any

* synchronization or volatile field accesses.

protected final void setExclusiveOwnerThread(Thread t) {

   exclusiveOwnerThread = t;

}

Note:exclusiveOwnerThread【The current owner of exclusive mode synchronization, private transient Thread exclusiveOwnerThread】是AbstractOwnableSynchronizer的成員變量【AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer】。

 

public final void acquire(int arg) {

  if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

    selfInterrupt();

}

這裏acquire以獨佔模式獲取對象而且忽略中斷。經過至少調用一次tryAcquire(int)來實現此方法並在成功時返回。不然在成功以前一直調用tryAcquire(int)將線程加入隊列,線程可能重複被阻塞或不被阻塞。可使用此方法來實現Lock.lock()方法。

Note:tryAcquire試圖在獨佔模式下獲取對象狀態,此方法應該查詢是否容許它在獨佔模式下獲取對象狀態,若是容許則獲取它。此方法老是由執行acquire的線程來調用。若是此方法報告失敗,則acquire方法能夠將線程加入隊列(若是尚未將它加入隊列),直到得到其餘某個線程釋放了該線程的信號。能夠用此方法來實現Lock.tryLock()方法。

實現原理:

1.當前線程首先經過tryAcquire()嘗試獲取鎖,獲取成功直接返回;嘗試失敗則進入到等待隊列排序等待
2.當前線程嘗試失敗,先經過addWaiter(Node.EXCLUSIVE)來將當前線程加入到CLH隊列,執行完addWaiter(Node.EXCLUSIVE)以後調用acquireQueued()來獲取鎖
3.當前線程在執行acquireQueued()時,會進入到CLH隊列中休眠等待,直到獲取鎖了才返回,若是當前線程在休眠等待過程當中被中斷過,acquireQueued會返回true,此時當前線程會調用selfInterrupt()給本身產生中斷

 

FairSync中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();

 // 獲取同步狀態state

   int c = getState();

      if (c == 0) {

        // 隊列中不存在等待更長時間的線程(隊列中的首個線程)

          // 是首個線程則獲取該鎖而且設置狀態

        if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {

           // 設置爲exclusiveOwnerThread

           setExclusiveOwnerThread(current);

           return true;

         }               

// 獲取exclusiveOwnerThread而且是當前線程時

      } else if (current == getExclusiveOwnerThread()) {

        int nextc = c + acquires;

        if (nextc < 0)

           throw new Error("Maximum lock count exceeded");

      setState(nextc); // 設置同步狀態state

         return true;

      }

      return false;

   }

}

Note:tryAcquire只是嘗試獲取鎖,成功則返回true,失敗則返回false,後續再去獲取。這裏涉及到的state表示鎖的狀態,對於獨佔鎖state=0表示鎖是可獲取狀態,即鎖沒有被任何線程鎖持有,因爲Java中的獨佔鎖是可重入的,故state的值能夠大於1。

 

hasQueuedPredecessors源碼分析:

* Queries whether any threads have been waiting to acquire longer than the current thread. Note that because cancellations due to interrupts and timeouts may occur at any time, a {@code true} return does not guarantee that some other thread will acquire before the current thread.   

public final boolean hasQueuedPredecessors() {

  // The correctness of this depends on head being initialized

  // before tail and on head.next being accurate if the current

  // thread is first in queue.

  Node t = tail; // Read fields in reverse initialization order

  Node h = head; // Node爲AbstractQueuedSynchronizer中的一個內部類

  Node s;

  return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());

}

實現原理:hasQueuedPredecessors經過判斷當前線程是否是在CLH隊列的隊首來返回AQS中是否是有比當前線程等待更久的線程。首先判斷state的值,當state爲0時,若是隊列中不存在等待的線程而且state符合預期值就直接設置爲獨佔線程同時更新state值,返回成功。當state不爲0時,而且當前線程是獨佔線程就直接更新state的值。其它情形下都直接返回false

 

NonfairSync中tryAcquire源碼實現:

protected final boolean tryAcquire(int acquires) {

   return nonfairTryAcquire(acquires);

}

*Performs non-fair tryLock.  tryAcquire is implemented in subclasses, but both need nonfair try for trylock method.

final boolean nonfairTryAcquire(int acquires) {

  final Thread current = Thread.currentThread();

  int c = getState(); // 0表示鎖沒有被任何線程鎖擁有

  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的值,當state爲0時,若是state符合預期值就直接設置爲獨佔線程,同時也會更新state值,返回成功。當state不爲0時,而且當前線程是獨佔線程就直接更新state的值,這裏可能存在overflow的情形。其它情形下都直接返回false。

相關文章
相關標籤/搜索