在Java多線程:線程間通訊之Lock中咱們提到了ReentrantLock是API級別的實現,可是沒有說明其具體實現原理。實際上,ReentrantLock的底層實現使用了AQS(AbstractQueueSynchronizer)。AQS自己僅僅是一個框架,定義了一套多線程訪問共享資源的同步框架,能夠實現ReentrantLock, Semaphore, CountDownLatch等多線程類。html
AQS框架維護了一個資源state(volatile int)和一個同步隊列。其中對state的訪問包括三種方法:getState(), setState(), compareAndSetState()。其中,compareAndSetState()是原子操做,底層是CAS實現。java
AQS框架包含兩種可供選擇的實現方式:獨佔(Exclusive)和共享(Share)。因爲不一樣自定義同步器徵用共享資源的方式不一樣,自定義同步器實現時只需實現共享資源state的獲取與釋放方式便可,而不須要考慮隊列的維護。下面簡述AQS框架中獨佔鎖和共享鎖的獲取,釋放流程。多線程
獲取時首先調用acquire(acquires),以後進入tryAcquire(acquires)嘗試獲取鎖,若成功則返回。若失敗則將當前線程構造爲Node節點,CAS插入到同步隊列尾部,該線程自旋。自旋時判斷其前驅節點是否爲頭節點,是否成功獲取同步狀態,兩者皆成立則當前節點設置爲頭節點,不然掛起當前線程等待被前驅節點喚醒。併發
釋放時首先調用release(acquires),以後進入tryRelease(acquires)釋放同步狀態,以後獲取同步隊列中當前節點的下一節點並喚醒。框架
獲取時首先調用acquireShared(acquires),以後進入tryAcquireShared(acquires)獲取同步狀態,返回值不小於0則說明同步狀態有剩餘,獲取成功直接返回。若返回值小於0則說明獲取同步狀態失敗,構造Node節點CAS插入同步隊列尾部並自旋檢查前驅節點是否爲頭節點且成功獲取同步狀態,如果則當前節點設爲頭節點,不然掛起等待被前驅節點喚醒。ui
釋放時調用releaseShared(acquires)釋放同步狀態,以後遍歷整個隊列喚醒全部後繼節點。.net
Java中的ReentrantLock和synchronized都是可重入鎖,synchronized由JVM實現,重入鎖實現時最主要的邏輯是判斷上次獲取鎖的線程是否爲當前線程,ReentrantLock基於AQS實現,提供公平鎖和非公平鎖兩種方式,非公平鎖實現邏輯以下:線程
final boolean nonfairTryAcquire(int acquires) { //獲取當前線程 final Thread current = Thread.currentThread(); //經過AQS獲取同步狀態 int c = getState(); //同步狀態爲0,說明臨界區處於無鎖狀態, if (c == 0) { //修改同步狀態,即加鎖 if (compareAndSetState(0, acquires)) { //將當前線程設置爲鎖的owner 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; }
公平鎖的實現邏輯以下,與非公平鎖的區別爲判斷當前節點是否存在前驅節點,只有等待前驅節點釋放後才能獲取鎖。3d
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; }
Java的ReentrantReadWriteLock是讀寫鎖實現,其原理是將state變量的高16位和低16位拆分,高16位表示讀鎖,低16位表示寫鎖。其寫鎖tryAcquire(acquires)實現以下:code
其讀鎖的tryAcquire(acquires)實現以下:
寫寫鎖釋放與普通獨佔鎖基本相同,在寫鎖釋放中不斷減小讀鎖的同步狀態,同步狀態爲0時才能徹底釋放;讀鎖釋放過程當中不斷釋放寫鎖狀態,直到爲0,表示沒有線程獲取讀鎖。