蒼穹之邊,浩瀚之摯,眰恦之美; 悟心悟性,善始善終,惟善惟道! —— 朝槿《朝槿兮年說》

寫在開頭

在并發(fā)編程領域,有兩大核心問題:一個是互斥,即同一時刻只允許一個線程訪問共享資源;另一個是同步,即線程之間如何通信、協(xié)作。<br />主要原因是,對于多線程實現(xiàn)實現(xiàn)并發(fā),一直以來,多線程都存在2個問題:
- 線程之間內(nèi)存共享,需要通過加鎖進行控制,但是加鎖會導致性能下降,同時復雜的加鎖機制也會增加編程編碼難度
- 過多線程造成線程之間的上下文切換,導致效率低下
因此,在并發(fā)編程領域中,一直有一個很重要的設計原則: “ 不要通過內(nèi)存共享來實現(xiàn)通信,而應該通過通信來實現(xiàn)內(nèi)存共享。”<br />簡單來說,就是盡可能通過消息通信,而不是內(nèi)存共享來實現(xiàn)進程或者線程之間的同步。
關健術語

<br />本文用到的一些關鍵詞語以及常用術語,主要如下:
- 并發(fā)(Concurrent): 在操作系統(tǒng)中,是指一個時間段中有幾個程序都處于已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行。
- 并行(Parallel): 當系統(tǒng)有一個以上CPU時,當一個CPU執(zhí)行一個進程時,另一個CPU可以執(zhí)行另一個進程,兩個進程互不搶占CPU資源,可以同時進行。
- 信號量(Semaphore): 是在多線程環(huán)境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被并發(fā)調(diào)用,也是作系統(tǒng)用來解決并發(fā)中的互斥和同步問題的一種方法。
- 信號量機制(Semaphores): 用來解決同步/互斥的問題的,它是1965年,荷蘭學者 Dijkstra提出了一種卓有成效的實現(xiàn)進程互斥與同步的方法。
- 管程(Monitor) : 一般是指管理共享變量以及對共享變量的操作過程,讓它們支持并發(fā)的一種機制。
- 互斥(Mutual Exclusion):一個公共資源同一時刻只能被一個進程或線程使用,多個進程或線程不能同時使用公共資源。即就是同一時刻只允許一個線程訪問共享資源的問題。
- 同步(Synchronization):兩個或兩個以上的進程或線程在運行過程中協(xié)同步調(diào),按預定的先后次序運行。即就是線程之間如何通信、協(xié)作的問題。
- 對象池(Object Pool): 指的是一次性創(chuàng)建出 N 個對象,之后所有的線程重復利用這 N 個對象,當然對象在被釋放前,也是不允許其他線程使用的, 一般指保存實例對象的容器。
基本概述
在Java領域中,我們可以將鎖大致分為基于Java語法層面(關鍵詞)實現(xiàn)的鎖和基于JDK層面實現(xiàn)的鎖。

在Java領域中, 尤其是在并發(fā)編程領域,對于多線程并發(fā)執(zhí)行一直有兩大核心問題:同步和互斥。其中:
- 互斥(Mutual Exclusion):一個公共資源同一時刻只能被一個進程或線程使用,多個進程或線程不能同時使用公共資源。即就是同一時刻只允許一個線程訪問共享資源的問題。
- 同步(Synchronization):兩個或兩個以上的進程或線程在運行過程中協(xié)同步調(diào),按預定的先后次序運行。即就是線程之間如何通信、協(xié)作的問題。
針對對于這兩大核心問題,利用管程是能夠解決和實現(xiàn)的,因此可以說,管程是并發(fā)編程的萬能鑰匙。<br />雖然,Java在基于語法層面(synchronized 關鍵字)實現(xiàn)了對管程技術,但是從使用方式和性能上來說,內(nèi)置鎖(synchronized 關鍵字)的粒度相對過大,不支持超時和中斷等問題。<br />為了彌補這些問題,從JDK層面對其“重復造輪子”,在JDK內(nèi)部對其重新設計和定義,甚至實現(xiàn)了新的特性。<br />在Java領域中,從JDK源碼分析來看,基于JDK層面實現(xiàn)的鎖大致主要可以分為以下4種方式:

- 基于Lock接口實現(xiàn)的鎖:JDK1.5版本提供的ReentrantLock類
- 基于ReadWriteLock接口實現(xiàn)的鎖:JDK1.5版本提供的ReentrantReadWriteLock類
- 基于AQS基礎同步器實現(xiàn)的鎖:JDK1.5版本提供的并發(fā)相關的同步器Semaphore,CyclicBarrier以及CountDownLatch等
- 基于自定義API操作實現(xiàn)的鎖:JDK1.8版本中提供的StampedLock類
從閱讀源碼不難發(fā)現(xiàn),在Java SDK 并發(fā)包主要通過AbstractQueuedSynchronizer(AQS)實現(xiàn)多線程同步機制的封裝與定義,而通過Lock 和 Condition 兩個接口來實現(xiàn)管程,其中 Lock 用于解決互斥問題,Condition 用于解決同步問題。
一.AQS基礎同步器基本理論
在Java領域中,同步器是專門為多線程并發(fā)設計的同步機制,主要是多線程并發(fā)執(zhí)行時線程之間通過某種共享狀態(tài)來實現(xiàn)同步,只有當狀態(tài)滿足這種條件時線程才往下執(zhí)行的一種同步機制。

<br />一個標準的AQS同步器主要有同步狀態(tài)機制,等待隊列,條件隊列,獨占模式,共享模式等五大核心要素組成。<br />在Java領域中,JDK的JUC(java.util.concurrent.)包中提供了各種并發(fā)工具,但是大部分同步工具的實現(xiàn)基于AbstractQueuedSynchronizer類實現(xiàn),其內(nèi)部結構主要如下:
- 同步狀態(tài)機制(Synchronization Status):主要用于實現(xiàn)鎖(Lock)機制,是指同步狀態(tài),其要求對于狀態(tài)的更新必須原子性的
- 等待隊列(Wait Queue):主要用于存放等待線程獲取到的鎖資源,并且把線程維護到一個Node(節(jié)點)里面和維護一個非阻塞的CHL Node FIFO(先進先出)隊列,主要是采用自旋鎖+CAS操作來保證節(jié)點插入和移除的原子性操作。
- 條件隊列(Condition Queue):用于實現(xiàn)鎖的條件機制,一般主要是指替換“等待-通知”工作機制,主要是通過ConditionObject對象實現(xiàn)Condition接口提供的方法實現(xiàn)。
- 獨占模式(Exclusive Mode):主要用于實現(xiàn)獨占鎖,主要是基于靜態(tài)內(nèi)部類Node的常量標志EXCLUSIVE來標識該節(jié)點是獨占模式
- 共享模式(Shared Mode):主要用于實現(xiàn)共享鎖,主要是基于靜態(tài)內(nèi)部類Node的常量標志SHARED來標識該節(jié)點是共享模式

- 條件變量(Conditional Variable): 利用線程間共享的變量進行同步的一種工作機制
- 共享變量((Shared Variable)):一般指對象實體對象的成員變量和屬性
- 阻塞隊列(Blocking Queue):共享變量(Shared Variable)及其對共享變量的操作統(tǒng)一封裝
- 等待隊列(Wait Queue):每個條件變量都對應有一個等待隊列(Wait Queue),內(nèi)部需要實現(xiàn)入隊操作(Enqueue)和出隊操作(Dequeue)方法
- 變量狀態(tài)描述機(Synchronization Status):描述條件變量和共享變量之間狀態(tài)變化,又可以稱其為同步狀態(tài)
- 工作模式(Operation Mode): 線程資源具有排他性,因此定義獨占模式和共享模式兩種工作模式
綜上所述,條件變量和等待隊列的作用是解決線程之間的同步問題;共享變量與阻塞隊列的作用是解決線程之間的互斥問題。
二. JDK顯式鎖統(tǒng)一概念模型
在并發(fā)編程領域,有兩大核心問題:一個是互斥,即同一時刻只允許一個線程訪問共享資源;另一個是同步,即線程之間如何通信、協(xié)作。

綜合Java領域中的并發(fā)鎖的各種實現(xiàn)與應用分析來看,一把鎖或者一種鎖,基本上都會包含以下幾個方面:
- 鎖的同步器工作機制:主要是考慮共享模式還是獨享模式,是否支持超時機制,以及是否支持超時機制?
- 鎖的同步器工作模式:主要是基于AQS基礎同步器封裝內(nèi)部同步器,是否考慮公平/非公平模式?
- 鎖的狀態(tài)變量機制: 主要鎖的狀態(tài)設置,是否共享狀態(tài)變量?
- 鎖的隊列封裝定義:主要是指等待隊列和條件隊列,是否需要條件隊列或者等待隊列定義?
- 鎖的底層實現(xiàn)操作: 主要是指底層CL鎖和CAS操作,是否需要考慮自旋鎖或者CAS操作實例對象方法?
- 鎖的組合實現(xiàn)新鎖: 主要是基于獨占鎖和共享鎖,是否考慮對應API自定義操作實現(xiàn)?
綜上所述,大致可以根據(jù)上述這些方向,我們便可以清楚???知道Java領域中各種鎖實現(xiàn)的基本理論時和實現(xiàn)思想。
五.StampedLock(印戳鎖)的設計與實現(xiàn)
在Java領域中,StampedLock(印戳鎖)是針對于Java多線程并發(fā)控制中引入一個共享鎖定義讀操作與獨占鎖定義讀操作等場景共同組合構成一把鎖來提高并發(fā),主要是基于自定義API操作實現(xiàn)的一種并發(fā)控制工具類。

1. 設計思想

<br />StampedLock(印戳鎖)是對ReentrantReadWriteLock讀寫鎖的一 種改進,主要的改進為:在沒有寫只有讀的場景下,StampedLock支持 不用加讀鎖而是直接進行讀操作,最大程度提升讀的效率,只有在發(fā) 生過寫操作之后,再加讀鎖才能進行讀操作。<br />一般來說,StampedLock 里的寫鎖和悲觀讀鎖加鎖成功之后,都會返回一個 stamp;然后解鎖的時候,需要傳入這個 stamp。
1.1 印戳鎖的基本理論
雖然基于AQS基礎同步器實現(xiàn)了各種鎖,但是由于采用的自旋鎖+CAS操作方式會導致如下兩個問題:
- CAS惡性空自旋會浪費大量的CPU資源
- 在SMP架構的CPU上會導致“總線風暴”問題
解決CAS惡性空自旋的有效方式之一是以空間換時間,較為常見的 方案有兩種:分散操作熱點和使用隊列削峰。<br />基于這個基礎,在JDK1.8版本中,基于使用隊列削峰的方式,自定義API操作,提供了StampedLock(印戳鎖)的實現(xiàn)。<br />簡單來說,StampedLock(印戳鎖)提供了三種鎖的實現(xiàn)模式,其中:
- 悲觀讀鎖:與ReadWriteLock的讀鎖類似,多個線程可以同 時獲取悲觀讀鎖,悲觀讀鎖是一個共享鎖。
- 樂觀讀鎖:相當于直接操作數(shù)據(jù),不加任何鎖,連讀鎖都不 要。
- 寫鎖:與ReadWriteLock的寫鎖類似,寫鎖和悲觀讀鎖是互 斥的。雖然寫鎖與樂觀讀鎖不會互斥,但是在數(shù)據(jù)被更新之后,之前 通過樂觀讀鎖獲得的數(shù)據(jù)已經(jīng)變成了臟數(shù)據(jù)。
1.1 印戳鎖的實現(xiàn)思想
StampedLock(印戳鎖)與其他顯式鎖不同的是,主要是是最早在JDK1.8版本中提供的,從設計思想上來看,主要包括共享狀態(tài)變量機制,內(nèi)置的等待數(shù)據(jù)隊列,讀鎖視圖,寫鎖視圖以及讀寫鎖視圖等5個核心要素。其中:
- 共享狀態(tài)變量機制:主要是在內(nèi)部封裝一些靜態(tài)私有的常量,用于描述各個模式之間的狀態(tài)描述等。
- 內(nèi)置的等待數(shù)據(jù)隊列:主要是自定義實現(xiàn)一個基于CLH鎖的等待隊列
- 讀鎖視圖:基于Lock接口實現(xiàn)一個對應讀鎖的視圖
- 寫鎖視圖:基于Lock接口實現(xiàn)一個對應寫鎖的視圖
- 讀寫鎖視圖:基于ReadWriteLock接口實現(xiàn)一個包含讀鎖和寫鎖的視圖
2. 基本實現(xiàn)

在StampedLock(印戳鎖)類的JDK1.8版本中,對于StampedLock的基本實現(xiàn)如下:
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
private static final long serialVersionUID = -6001602636862214147L;
/** StampedLock鎖-自旋控制的最大允許核心線程數(shù) */
private static final int NCPU = Runtime.getRuntime().availableProcessors();
/** StampedLock鎖-等待隊列自旋控制的最大自旋閾值 */
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
/** StampedLock鎖-等待隊列頭節(jié)點自旋控制的最大自旋閾值 */
private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
/** StampedLock鎖-等待隊列頭節(jié)點自旋控制的最大自旋閾值 */
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
/** StampedLock鎖-進入阻塞之前的最大重試次數(shù) */
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
//... 其他鎖資源的狀態(tài)常量
/** StampedLock鎖-CLH隊列的頭部(head)節(jié)點 */
private transient volatile WNode whead;
/** StampedLock鎖-CLH隊列的尾部(tail)節(jié)點 */
private transient volatile WNode wtail;
/** StampedLock鎖-讀鎖視圖*/
transient ReadLockView readLockView;
/** StampedLock鎖-寫鎖視圖*/
transient WriteLockView writeLockView;
/** StampedLock鎖-讀寫鎖視圖 */
transient ReadWriteLockView readWriteLockView;
/** StampedLock鎖-鎖的最原始的狀態(tài)初始值 */
private static final long ORIGIN = WBIT << 1;
/** StampedLock鎖-各種鎖的同步狀態(tài)變量 */
private transient volatile long state;
/** StampedLock鎖-讀鎖的溢出的拓展標記 */
private transient int readerOverflow;
/** StampedLock鎖-構造方法 */
public StampedLock() {
state = ORIGIN;
}
/** StampedLock鎖-實例化ReadLock方法 */
public Lock asReadLock() {
ReadLockView v;
return ((v = readLockView) != null ? v :
(readLockView = new ReadLockView()));
}
/** StampedLock鎖-實例化WriteLock方法 */
public Lock asWriteLock() {
WriteLockView v;
return ((v = writeLockView) != null ? v :
(writeLockView = new WriteLockView()));
}
/** StampedLock鎖-實例化ReadWriteLock方法 */
public ReadWriteLock asReadWriteLock() {
ReadWriteLockView v;
return ((v = readWriteLockView) != null ? v :
(readWriteLockView = new ReadWriteLockView()));
}
/** StampedLock鎖-獲取ReadLock方法 */
public long readLock() {
long s = state, next; // bypass acquireRead on common uncontended case
return ((whead == wtail && (s & ABITS) < RFULL &&
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L));
}
/** StampedLock鎖-獲取WriteLock方法 */
public long writeLock() {
long s, next; // bypass acquireWrite in fully unlocked case only
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : acquireWrite(false, 0L));
}
//... 其他代碼
}
2.1 共享狀態(tài)變量機制
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-自旋控制的最大允許核心線程數(shù) */
private static final int NCPU = Runtime.getRuntime().availableProcessors();
/** StampedLock鎖-等待隊列自旋控制的最大自旋閾值 */
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
/** StampedLock鎖-等待隊列頭節(jié)點自旋控制的最大自旋閾值 */
private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
/** StampedLock鎖-等待隊列頭節(jié)點自旋控制的最大自旋閾值 */
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
/** StampedLock鎖-進入阻塞之前的最大重試次數(shù) */
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
// Values for lock state and stamp operations
/** StampedLock鎖-讀鎖移動的位數(shù) */
private static final long RUNIT = 1L;
/** StampedLock鎖-寫鎖移動的位數(shù) */
private static final long WBIT = 1L << LG_READERS;
/** StampedLock鎖-讀鎖移動的位數(shù) */
private static final long RBITS = WBIT - 1L;
/** StampedLock鎖-讀鎖移動的位數(shù) */
private static final long RFULL = RBITS - 1L;
/** StampedLock鎖-讀寫鎖移動的位數(shù) */
private static final long ABITS = RBITS | WBIT;
/** StampedLock鎖-讀寫鎖移動的位數(shù) */
private static final long SBITS = ~RBITS;
// Special value from cancelled acquire methods so caller can throw IE
/** StampedLock鎖-線程對象中斷標識 */
private static final long INTERRUPTED = 1L;
// Values for node status; order matters
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
private static final int WAITING = -1;
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
private static final int CANCELLED = 1;
// Modes for nodes (int not boolean to allow arithmetic)
/** StampedLock鎖-用于表示在隊列之中是讀模式 */
private static final int RMODE = 0;
/** StampedLock鎖-用于表示在隊列之中是寫模式 */
private static final int WMODE = 1;
//... 其他代碼
// Unsafe mechanics
/** StampedLock鎖-實例化Unsafe對象 */
private static final sun.misc.Unsafe U;
/** StampedLock鎖-狀態(tài) */
private static final long STATE;
/** StampedLock鎖-頭部節(jié)點 */
private static final long WHEAD;
/** StampedLock鎖-尾部節(jié)點 */
private static final long WTAIL;
/** StampedLock鎖-后繼節(jié)點 */
private static final long WNEXT;
/** StampedLock鎖-節(jié)點狀態(tài) */
private static final long WSTATUS;
/** StampedLock鎖-節(jié)點鏈表 */
private static final long WCOWAIT;
/** StampedLock鎖-中斷標識 */
private static final long PARKBLOCKER;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = StampedLock.class;
Class<?> wk = WNode.class;
STATE = U.objectFieldOffset
(k.getDeclaredField("state"));
WHEAD = U.objectFieldOffset
(k.getDeclaredField("whead"));
WTAIL = U.objectFieldOffset
(k.getDeclaredField("wtail"));
WSTATUS = U.objectFieldOffset
(wk.getDeclaredField("status"));
WNEXT = U.objectFieldOffset
(wk.getDeclaredField("next"));
WCOWAIT = U.objectFieldOffset
(wk.getDeclaredField("cowait"));
Class<?> tk = Thread.class;
PARKBLOCKER = U.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
} catch (Exception e) {
throw new Error(e);
}
}
}
對于StampedLock鎖中對于各種資源的標記,其封裝了一系列的常量,主要可以分為以下幾個方面,其中:
- 核心資源常量標識:是對線程操作資源的提供的常量封裝,其中:
- NCPU:自旋控制的核心線程數(shù)量,主要通過Runtime.getRuntime().availableProcessors()獲取設置。
- SPINS:等待隊列自旋控制的最大自旋閾值,主要通過 (_NCPU _> 1) ? 1 << 6 : 0獲取設置
- HEAD_SPINS: 等待隊列頭節(jié)點自旋控制的自旋閾值,主要通過 (_NCPU _> 1) ? 1 << 10 : 0獲取設置
- MAX_HEAD_SPINS:等待隊列頭節(jié)點自旋控制的最大自旋閾值,主要通過(_NCPU _> 1) ? 1 << 16 : 0獲取設置
- OVERFLOW_YIELD_RATE:線程讓步操作等待的自旋閾值,默認值為7
- LG_READERS:讀鎖溢出的最大閾值,默認值為7
- INTERRUPTED:線程中斷標識,默認值為1L
- 鎖狀態(tài)值設置標識:
- ORIGIN:鎖狀態(tài)的初始值,默認值為WBIT << 1,如果分配失敗默認設置為0
- 鎖狀態(tài)的操作標識:
- RUNIT:讀鎖移動的位數(shù),默認值為 1
- WBIT:寫鎖移動的位數(shù),默認值為1L << LG_READERS
- RBITS:讀鎖移動的位數(shù),默認值為_WBIT _- 1L
- RFULL:移動的位數(shù),默認值為_RBITS _- 1L
- ABITS:鎖移動的位數(shù),默認值為 _RBITS _| WBIT
- SBITS:鎖移動的位數(shù),默認值為 ~RBITS
- 等待隊列節(jié)點標識:
- WAITING:等待狀態(tài)的初始值,默認值為-1
- CANCELLED:取消狀態(tài)的初始值,默認值為1
- 讀寫鎖的模式標識:
- RMODE:讀鎖模式,默認值為0
- WMODE:寫鎖模式,默認值為1
- CAS操作狀態(tài)標識:封裝了CAS操作狀態(tài)標識,還通過反射實例化了Unsafe對象實例。
2.2 內(nèi)置的等待隊列WNode
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** Wait nodes */
static final class WNode {
/** StampedLock鎖-隊列前驅節(jié)點 */
volatile WNode prev;
/** StampedLock鎖-隊列后驅節(jié)點 */
volatile WNode next;
/** StampedLock鎖-鎖的存儲列表 */
volatile WNode cowait; // list of linked readers
/** StampedLock鎖-線程對象 */
volatile Thread thread; // non-null while possibly parked
/** StampedLock鎖-鎖的狀態(tài) */
volatile int status; // 0, WAITING, or CANCELLED
/** StampedLock鎖-鎖的模式 */
final int mode; // RMODE or WMODE
WNode(int m, WNode p) { mode = m; prev = p; }
}
/** Head of CLH queue */
/** StampedLock鎖-頭部節(jié)點 */
private transient volatile WNode whead;
/** Tail (last) of CLH queue */
/** StampedLock鎖-尾部節(jié)點 */
private transient volatile WNode wtail;
}
對于StampedLock鎖對于等待隊列的實現(xiàn),主要包含以下幾個方面的內(nèi)容,其中:<br />

- 封裝了一個等待隊列WNode的靜態(tài)內(nèi)部類,其中:
- prev:等待隊列的前驅節(jié)點
- next:等待隊列的后驅節(jié)點
- cowait:表示依據(jù)鎖標記存儲當前線程入隊的情況,隊列鎖列表
- thread: 線程對象,一般都是當前獲取鎖的線程
- status:用于表示鎖的狀態(tài)變量,對應著常量0,WAITING(-1), CANCELLED(1),其中,0表示正常狀態(tài),WAITING(-1)為等待狀態(tài),CANCELLED(1)為取消狀態(tài)。
- mode:用于表示鎖的模式,對應著常量RMODE和WMODE,其中RMODE為寫模式,WMOD為讀模式
- 構造方法WNode(int m, WNode p):用于實例化WNode對象,實現(xiàn)一個等待隊列
- 實例化等待隊列對象,主要封裝一個頭部節(jié)點whead和尾部節(jié)點wtail的對象
2.3 共用的讀鎖核心處理邏輯
首先,對于StampedLock鎖的讀鎖視圖與寫鎖視圖的隊列操作,有一個核心的處理邏輯:
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-取消入隊列 */
private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
if (node != null && group != null) {
Thread w;
node.status = CANCELLED;
// unsplice cancelled nodes from group
for (WNode p = group, q; (q = p.cowait) != null;) {
if (q.status == CANCELLED) {
U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
p = group; // restart
}
else
p = q;
}
if (group == node) {
for (WNode r = group.cowait; r != null; r = r.cowait) {
if ((w = r.thread) != null)
U.unpark(w); // wake up uncancelled co-waiters
}
for (WNode pred = node.prev; pred != null; ) { // unsplice
WNode succ, pp; // find valid successor
while ((succ = node.next) == null ||
succ.status == CANCELLED) {
WNode q = null; // find successor the slow way
for (WNode t = wtail; t != null && t != node; t = t.prev)
if (t.status != CANCELLED)
q = t; // don't link if succ cancelled
if (succ == q || // ensure accurate successor
U.compareAndSwapObject(node, WNEXT,
succ, succ = q)) {
if (succ == null && node == wtail)
U.compareAndSwapObject(this, WTAIL, node, pred);
break;
}
}
if (pred.next == node) // unsplice pred link
U.compareAndSwapObject(pred, WNEXT, node, succ);
if (succ != null && (w = succ.thread) != null) {
succ.thread = null;
U.unpark(w); // wake up succ to observe new pred
}
if (pred.status != CANCELLED || (pp = pred.prev) == null)
break;
node.prev = pp; // repeat if new pred wrong/cancelled
U.compareAndSwapObject(pp, WNEXT, pred, succ);
pred = pp;
}
}
}
WNode h; // Possibly release first waiter
while ((h = whead) != null) {
long s; WNode q; // similar to release() but check eligibility
if ((q = h.next) == null || q.status == CANCELLED) {
for (WNode t = wtail; t != null && t != h; t = t.prev)
if (t.status <= 0)
q = t;
}
if (h == whead) {
if (q != null && h.status == 0 &&
((s = state) & ABITS) != WBIT && // waiter is eligible
(s == 0L || q.mode == RMODE))
release(h);
break;
}
}
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
}
}
其次,對于StampedLock鎖的讀鎖視圖的實現(xiàn)作來看,主要核心處理如下:
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-獲取讀鎖 */
private long acquireRead(boolean interruptible, long deadline) {
WNode node = null, p;
for (int spins = -1;;) {
WNode h;
if ((h = whead) == (p = wtail)) {
for (long m, s, ns;;) {
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
return ns;
else if (m >= WBIT) {
if (spins > 0) {
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else {
if (spins == 0) {
WNode nh = whead, np = wtail;
if ((nh == h && np == p) || (h = nh) != (p = np))
break;
}
spins = SPINS;
}
}
}
}
if (p == null) { // initialize queue
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
}
else if (node == null)
node = new WNode(RMODE, p);
else if (h == p || p.mode != RMODE) {
if (node.prev != p)
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;
}
}
else if (!U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node))
node.cowait = null;
else {
for (;;) {
WNode pp, c; Thread w;
if ((h = whead) != null && (c = h.cowait) != null &&
U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null) // help release
U.unpark(w);
if (h == (pp = p.prev) || h == p || pp == null) {
long m, s, ns;
do {
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s,
ns = s + RUNIT) :
(m < WBIT &&
(ns = tryIncReaderOverflow(s)) != 0L))
return ns;
} while (m < WBIT);
}
if (whead == h && p.prev == pp) {
long time;
if (pp == null || h == p || p.status > 0) {
node = null; // throw away
break;
}
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, p, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if ((h != pp || (state & ABITS) == WBIT) &&
whead == h && p.prev == pp)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, p, true);
}
}
}
}
for (int spins = -1;;) {
WNode h, np, pp; int ps;
if ((h = whead) == p) {
if (spins < 0)
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
spins <<= 1;
for (int k = spins;;) { // spin at head
long m, s, ns;
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
WNode c; Thread w;
whead = node;
node.prev = null;
while ((c = node.cowait) != null) {
if (U.compareAndSwapObject(node, WCOWAIT,
c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
return ns;
}
else if (m >= WBIT &&
LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
break;
}
}
else if (h != null) {
WNode c; Thread w;
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
}
if (whead == h) {
if ((np = node.prev) != p) {
if (np != null)
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {
if ((pp = p.prev) != null) {
node.prev = pp;
pp.next = node;
}
}
else {
long time;
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 &&
(p != h || (state & ABITS) == WBIT) &&
whead == h && node.prev == p)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, node, true);
}
}
}
}
}
然后,對于StampedLock鎖的寫鎖視圖的實現(xiàn)作來看,主要核心處理如下:
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-獲取寫鎖 */
private long acquireWrite(boolean interruptible, long deadline) {
WNode node = null, p;
for (int spins = -1;;) { // spin while enqueuing
long m, s, ns;
if ((m = (s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
return ns;
}
else if (spins < 0)
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else if ((p = wtail) == null) { // initialize queue
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
}
else if (node == null)
node = new WNode(WMODE, p);
else if (node.prev != p)
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;
}
}
for (int spins = -1;;) {
WNode h, np, pp; int ps;
if ((h = whead) == p) {
if (spins < 0)
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
spins <<= 1;
for (int k = spins;;) { // spin at head
long s, ns;
if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s,
ns = s + WBIT)) {
whead = node;
node.prev = null;
return ns;
}
}
else if (LockSupport.nextSecondarySeed() >= 0 &&
--k <= 0)
break;
}
}
else if (h != null) { // help release stale waiters
WNode c; Thread w;
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
}
if (whead == h) {
if ((np = node.prev) != p) {
if (np != null)
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {
if ((pp = p.prev) != null) {
node.prev = pp;
pp.next = node;
}
}
else {
long time; // 0 argument to park means no timeout
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
whead == h && node.prev == p)
U.park(false, time); // emulate LockSupport.park
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, node, true);
}
}
}
}
}
最后,綜合對于StampedLock鎖的讀鎖和寫鎖的獲取和釋放等操作來看,主要核心處理都會調(diào)用以下2個方法,其中:
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-讀鎖溢出遞增處理方法 */
private long tryIncReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
++readerOverflow;
state = s;
return s;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
return 0L;
}
/** StampedLock鎖-讀鎖溢出遞減處理方法 */
private long tryDecReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
int r; long next;
if ((r = readerOverflow) > 0) {
readerOverflow = r - 1;
next = s;
}
else
next = s - RUNIT;
state = next;
return next;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
return 0L;
}
}
- tryIncReaderOverflow()方法:主要是實現(xiàn)對于鎖獲取自旋時最大重試次數(shù)的遞增運算。其中:
- 對于滿足stamp >= RFULL條件時,利用compareAndSwapLong()方法來實現(xiàn)CAS操作加持修改狀態(tài)值。對于readerOverflow作自增運算后返回一個stamp,可能存在更新和釋放操作。
- 否則,利用LockSupport.nextSecondarySeed() 判斷,對于線程做讓步處理,默認返回0
- tryDecReaderOverflow()方法:主要是實現(xiàn)對于鎖獲取自旋時最大重試次數(shù)的遞減運算。其中:
- 對于滿足stamp == RFULL條件時,利用compareAndSwapLong()方法來實現(xiàn)CAS操作加持修改狀態(tài)值。對于readerOverflow>0做遞減運算后返回一個stamp,可能存在更新和釋放操作。
- 否則,利用LockSupport.nextSecondarySeed() 判斷,對于線程做讓步處理,默認返回0
2.4 基于Lock接口實現(xiàn)的ReadLockView
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-ReadLockView */
final class ReadLockView implements Lock {
/** StampedLock鎖-獲取鎖 */
public void lock() { readLock(); }
/** StampedLock鎖-獲取可中斷鎖 */
public void lockInterruptibly() throws InterruptedException {
readLockInterruptibly();
}
/** StampedLock鎖-嘗試獲取鎖 */
public boolean tryLock() { return tryReadLock() != 0L; }
/** StampedLock鎖-嘗試獲取可超時鎖 */
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return tryReadLock(time, unit) != 0L;
}
/** StampedLock鎖-釋放 */
public void unlock() { unstampedUnlockRead(); }
/** StampedLock鎖-不支持條件變量定義 */
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}
/** StampedLock鎖-實例化ReadLock方法 */
public Lock asReadLock() {
ReadLockView v;
return ((v = readLockView) != null ? v :
(readLockView = new ReadLockView()));
}
/** StampedLock鎖-實例化ReadLock方法 */
public long readLock() {
long s = state, next; // bypass acquireRead on common uncontended case
return ((whead == wtail && (s & ABITS) < RFULL &&
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L));
}
/** StampedLock鎖-實例化ReadLock方法 */
public long tryReadLock() {
for (;;) {
long s, m, next;
if ((m = (s = state) & ABITS) == WBIT)
return 0L;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
}
/** StampedLock鎖-實例化ReadLock方法 */
public long tryReadLock(long time, TimeUnit unit)
throws InterruptedException {
long s, m, next, deadline;
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {
if ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
if (nanos <= 0L)
return 0L;
if ((deadline = System.nanoTime() + nanos) == 0L)
deadline = 1L;
if ((next = acquireRead(true, deadline)) != INTERRUPTED)
return next;
}
throw new InterruptedException();
}
/** StampedLock鎖-釋放鎖方法 */
final void unstampedUnlockRead() {
// 自旋操作
for (;;) {
long s, m; WNode h;
if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
throw new IllegalMonitorStateException();
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
}
}
}
對于ReadLock的實現(xiàn),主要包含以下幾個方面的內(nèi)容,其中:
- 基本實現(xiàn)方式:基于Lock接口實現(xiàn),提供了對應的鎖獲取和釋放操作方法,其中:
- lock()方法:一般模式,主要通過StampedLock類中readLock()方法實現(xiàn)
- lockInterruptibly()方法:可中斷模式,主要通過StampedLock類中readLockInterruptibly()方法實現(xiàn)
- 無參數(shù)tryLock() 方法:嘗試獲取鎖,主要依據(jù)StampedLock類中tryReadLock() != 0L來實現(xiàn)
- 有參數(shù)tryLock() 方法:嘗試獲取鎖,主要依據(jù)StampedLock類中tryReadLock(long time, TimeUnit unit)!= 0L來實現(xiàn)
- unlock()方法:鎖的釋放,主要通過StampedLock類中unstampedUnlockRead()方法實現(xiàn)
- newCondition() 方法:不支持條件變量的定義,默認設置拋出UnsupportedOperationException
- 對應處理方法:主要是在StampedLock外層實現(xiàn)的操作方法,其中:
- readLock()方法:讀鎖的實現(xiàn),主要核心邏輯在acquireRead()方法
- tryReadLock()方法:嘗試獲取讀鎖,核心處理邏輯是根據(jù)對應的條件返回對應的鎖的_stamp,否則拋出_InterruptedException。
- readLockInterruptibly()方法:讀鎖的可中斷機制實現(xiàn),核心處理邏輯是判斷線程是否中斷以及利用acquireRead方法驗證,條件成立時,返回鎖的_stamp,否則拋出_InterruptedException。
- unstampedUnlockRead()方法:釋放鎖,核心處理邏輯自旋操作+compareAndSwapLong實現(xiàn)。
2.5 基于Lock接口實現(xiàn)的WriteLockView
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
final class WriteLockView implements Lock {
public void lock() { writeLock(); }
public void lockInterruptibly() throws InterruptedException {
writeLockInterruptibly();
}
public boolean tryLock() { return tryWriteLock() != 0L; }
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return tryWriteLock(time, unit) != 0L;
}
public void unlock() { unstampedUnlockWrite(); }
public Condition newCondition() {
throw new UnsupportedOperationException();
}
}
/** StampedLock鎖-實例化WriteLock方法 */
public Lock asWriteLock() {
WriteLockView v;
return ((v = writeLockView) != null ? v :
(writeLockView = new WriteLockView()));
}
}
對于WriteLockView的實現(xiàn),主要包含以下幾個方面的內(nèi)容,其中:
- 基本實現(xiàn)方式:基于Lock接口實現(xiàn),提供了對應的鎖獲取和釋放操作方法,其中:
- lock()方法:一般模式,主要通過StampedLock類中WriteLock()方法實現(xiàn)
- lockInterruptibly()方法:可中斷模式,主要通過StampedLock類中writeLockInterruptibly()方法實現(xiàn)
- 無參數(shù)tryLock() 方法:嘗試獲取鎖,主要依據(jù)StampedLock類中tryWriteLock() != 0L來實現(xiàn)
- 有參數(shù)tryLock() 方法:嘗試獲取鎖,主要依據(jù)StampedLock類中tryWriteLock(long time, TimeUnit unit) != 0L來實現(xiàn)
- unlock()方法:鎖的釋放,主要通過StampedLock類中unstampedUnlockWrite()方法實現(xiàn)
- newCondition() 方法:不支持條件變量的定義,默認設置拋出UnsupportedOperationException
- 核心處理方法:主要是在StampedLock外層實現(xiàn)的操作方法,其中:
- writeLock()方法:寫鎖的實現(xiàn),主要核心邏輯在acquireWrite()方法
- tryWriteLock()方法:嘗試獲取寫鎖,核心處理邏輯是根據(jù)對應的條件返回對應的鎖的_stamp,否則拋出_InterruptedException。
- writeLockInterruptibly()方法:寫鎖的可中斷機制實現(xiàn),核心處理邏輯是判斷線程是否中斷以及利用acquireWrite方法驗證,條件成立時,返回鎖的_stamp,否則拋出_InterruptedException。
- unstampedUnlockWrite()方法:釋放鎖,核心處理邏輯主要是通過調(diào)用release(WNode h) 方法實現(xiàn)。
2.6 基于ReadWriteLock接口實現(xiàn)ReadWriteLockView
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-實例化ReadWriteLock方法 */
final class ReadWriteLockView implements ReadWriteLock {
/** StampedLock鎖-ReadLock方法 */
public Lock readLock() { return asReadLock(); }
/** StampedLock鎖-WriteLock方法 */
public Lock writeLock() { return asWriteLock(); }
}
/** StampedLock鎖-實例化ReadWriteLock方法 */
public ReadWriteLock asReadWriteLock() {
ReadWriteLockView v;
return ((v = readWriteLockView) != null ? v :
(readWriteLockView = new ReadWriteLockView()));
}
}
對于ReadWriteLockView的實現(xiàn),主要包含兩個部分,其中:
- 基于ReadWriteLock接口實現(xiàn),主要是實現(xiàn)readLock()和writeLock()方法
- 在asReadWriteLock()方法中,實例化ReadWriteLockView對象
3. 具體實現(xiàn)

對于StampedLock的具體實現(xiàn),我們可以從如下幾個方面拆解開來分析:
- 共享鎖ReadLock鎖獲取操作實現(xiàn): 需要區(qū)分悲觀讀鎖和樂觀讀鎖的獲取個有不同,一般有默認獲取方式和嘗試獲取兩種方式。
- 獨占鎖WriteLock寫鎖獲取操作實現(xiàn): 寫鎖與悲觀讀鎖互斥,一般有默認獲取方式和嘗試獲取兩種方式
- 共享鎖ReadLock鎖釋放操作實現(xiàn): 一般分為全釋放和半釋放ReadLock鎖操作兩種方式
- 獨占鎖WriteLock鎖釋放操作實現(xiàn):一般分為全釋放和半釋放WriteLock鎖操作兩種方式
接下來,我們便從具體的代碼中來分析以上內(nèi)容的基本實現(xiàn),以方便我們正確認識和了解StampedLock鎖。
3.1 共享鎖ReadLock讀鎖獲取操作實現(xiàn)
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-悲觀讀鎖-嘗試獲取鎖(默認模式,不支持超時機制) */
public long tryReadLock() {
// 鎖自旋轉+compareAndSwapLong來CAS操作加持
for (;;) {
long s, m, next;
// [1].直接返回0
if ((m = (s = state) & ABITS) == WBIT)
return 0L;
// [2].compareAndSwapLong來CAS操作加持
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
// [3].嘗試獲取讀鎖溢出處理
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
}
/** StampedLock鎖-悲觀讀鎖-嘗試獲取鎖(指定模式,支持超時機制) */
public long tryReadLock(long time, TimeUnit unit)
throws InterruptedException {
long s, m, next, deadline;
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {
if ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
if (nanos <= 0L)
return 0L;
if ((deadline = System.nanoTime() + nanos) == 0L)
deadline = 1L;
if ((next = acquireRead(true, deadline)) != INTERRUPTED)
return next;
}
throw new InterruptedException();
}
/** StampedLock鎖-樂觀讀鎖-嘗試獲取鎖 */
public long tryOptimisticRead() {
long s;
return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
}
}
對于讀鎖的獲取來說,都屬于是共享鎖,主要提供了以下幾種方式:
- 無參數(shù)tryReadLock()方法:悲觀讀鎖的獲取方式,默認模式,不支持超時機制
- 有參數(shù)tryReadLock()方法:悲觀讀鎖的獲取方式,指定參數(shù)模式,支持超時機制
- 無參數(shù)tryOptimisticRead()方法:樂觀讀鎖的獲取方式,沒有加鎖操作
3.2 獨占鎖WriteLock寫鎖獲取操作實現(xiàn)
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-獲取寫鎖操作(不支持超時機制) */
public long tryWriteLock() {
long s, next;
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : 0L);
}
/** StampedLock鎖-獲取寫鎖操作(支持超時機制) */
public long tryWriteLock(long time, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {
long next, deadline;
if ((next = tryWriteLock()) != 0L)
return next;
if (nanos <= 0L)
return 0L;
if ((deadline = System.nanoTime() + nanos) == 0L)
deadline = 1L;
if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
return next;
}
throw new InterruptedException();
}
}
對于寫鎖的獲取來說,都屬于是獨占鎖,主要提供了以下幾種方式:
- 無參數(shù)tryWriteLock()方法:默認模式,不支持超時機制
- 有參數(shù)tryWriteLock()方法:指定模式,依據(jù)參數(shù)來實現(xiàn),支持超時機制
3.3 共享鎖ReadLock釋放操作實現(xiàn)
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-釋放鎖操作 */
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L)
break;
else if (m == WBIT) {
if (a != m)
break;
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return;
}
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return;
}
throw new IllegalMonitorStateException();
}
/** StampedLock鎖-釋放讀鎖 */
public void unlockRead(long stamp) {
long s, m; WNode h;
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS) ||
(stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
throw new IllegalMonitorStateException();
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
}
}
/** StampedLock鎖-悲觀讀鎖-轉換升級并釋放處理 */
public long tryConvertToReadLock(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L) {
if (a != 0L)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
else if (m == WBIT) {
if (a != m)
break;
state = next = s + (WBIT + RUNIT);
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a != 0L && a < WBIT)
return stamp;
else
break;
}
return 0L;
}
/** StampedLock鎖-樂觀讀鎖-轉換升級并釋放處理 */
public long tryConvertToOptimisticRead(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
U.loadFence();
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS))
break;
if ((m = s & ABITS) == 0L) {
if (a != 0L)
break;
return s;
}
else if (m == WBIT) {
if (a != m)
break;
state = next = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return next & SBITS;
}
}
else if ((next = tryDecReaderOverflow(s)) != 0L)
return next & SBITS;
}
return 0L;
}
public boolean tryUnlockRead() {
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return true;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return true;
}
return false;
}
/** StampedLock鎖-嘗試釋放讀鎖 */
public boolean tryUnlockRead() {
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return true;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return true;
}
return false;
}
}
對于讀鎖的釋放來說,主要提供了以下幾種方式:
- unlock() 方法:依據(jù)鎖的狀態(tài)status來匹配對應鎖的stamp,然后釋放鎖操作
- unlockRead()方法: 依據(jù)鎖的狀態(tài)status來匹配對應讀鎖的stamp,然后釋放鎖操作
- tryUnlockRead()方法:釋放當前持有的讀鎖,會設置一個stamp然后返回true,否則,返回false
- tryConvertToReadLock()方法:依據(jù)鎖的狀態(tài)status來匹配對應讀鎖的stamp,然后根據(jù)對應情況處理。其中:
- 單寫鎖模式:一般返回一個對應讀鎖的stamp
- 悲觀讀模式:直接返回對應讀鎖的stamp
- 樂觀讀模式:需要獲取一個讀鎖,然后是立即返回對應讀鎖的stamp
- tryConvertToOptimisticRead(): 依據(jù)鎖的狀態(tài)status來匹配對應讀鎖的stamp,然后轉換升級處理釋放。其中:
- 悲觀讀模式:屬于一般讀鎖模式,返回的是檢測到對應讀鎖的stamp
- 樂觀讀模式:需要返回通過驗證的對應讀鎖的stamp
3.4 獨占鎖WriteLock寫鎖釋放操作實現(xiàn)
/** StampedLock鎖-最早在JDK1.8中實現(xiàn)的 */
public class StampedLock implements java.io.Serializable {
/** StampedLock鎖-鎖釋放方法(一般方法) */
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L)
break;
else if (m == WBIT) {
if (a != m)
break;
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return;
}
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return;
}
throw new IllegalMonitorStateException();
}
/** StampedLock鎖-寫鎖釋放方法 */
public void unlockWrite(long stamp) {
WNode h;
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
if ((h = whead) != null && h.status != 0)
release(h);
}
/** StampedLock鎖-寫鎖轉換升級處理并釋放鎖 */
public long tryConvertToWriteLock(long stamp) {
long a = stamp & ABITS, m, s, next;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L) {
if (a != 0L)
break;
if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
return next;
}
else if (m == WBIT) {
if (a != m)
break;
return stamp;
}
else if (m == RUNIT && a != 0L) {
if (U.compareAndSwapLong(this, STATE, s,
next = s - RUNIT + WBIT))
return next;
}
else
break;
}
return 0L;
}
/** StampedLock鎖-unlockWrite的核心實現(xiàn) */
private void release(WNode h) {
if (h != null) {
WNode q; Thread w;
U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
if ((q = h.next) == null || q.status == CANCELLED) {
for (WNode t = wtail; t != null && t != h; t = t.prev)
if (t.status <= 0)
q = t;
}
if (q != null && (w = q.thread) != null)
U.unpark(w);
}
}
}
對于寫鎖的釋放來說,主要提供了以下種方式:
- unlock() 方法:依據(jù)鎖的狀態(tài)status來匹配對應鎖的stamp,然后釋放鎖操作
- unlockWrite()方法:依據(jù)鎖的狀態(tài)status來匹配對應寫鎖的stamp,然后釋放鎖操作
- tryUnlockWrite()方法:釋放當前持有的寫鎖,會設置一個stamp然后返回true,否則,返回false
- tryConvertToWriteLock()方法:依據(jù)鎖的狀態(tài)status來匹配stamp,根據(jù)對應鎖的做升級處理。其中:
- 單寫鎖模式:直接返回對應的寫鎖標記stamp
- 讀寫鎖模式:需要釋放讀鎖鎖,并返回對應的寫鎖標記stamp
- 樂觀讀模式:直接返回對應的寫鎖標記stamp
綜上所述,StampedLock鎖本質上依然是一種讀寫鎖,只是沒有基于AQS基礎同步器來實現(xiàn),是自定義封裝API操作實現(xiàn)的。
寫在最后

通過對Java領域中,JDK內(nèi)部提供的各種鎖的實現(xiàn)來看,一直圍繞的核心主要還是基于AQS基礎同步器來實現(xiàn)的,但是AQS基礎同步器不是一種非它不可的技術標準規(guī)范,更多的只是一套技術參考指南。
但是,實際上,Java對于鎖的實現(xiàn)與運用遠遠不止這些,還有相位器(Phaser)和交換器(Exchanger),以及在Java JDK1.8版本之前并發(fā)容器ConcurrentHashMap中使用的分段鎖(Segment)。
不論是何種實現(xiàn)和應用,在Java并發(fā)編程領域來講,都是圍繞線程安全問題的角度去考慮的,只是針對于各種各樣的業(yè)務場景做的具體的實現(xiàn)。
一定意義上來講,對線程加鎖只是并發(fā)編程的實現(xiàn)方式之一,相對于實際應用來說,Java領域中的鎖都只是一種單一應用的鎖,只是給我們掌握Java并發(fā)編程提供一種思想沒,三言兩語也不可能詳盡。
到此為止,這算是對于Java領域中并發(fā)鎖的最終章,文中表述均為個人看法和個人理解,如有不到之處,忘請諒解也請給予批評指正。
最后,技術研究之路任重而道遠,愿我們熬的每一個通宵,都撐得起我們想在這條路上走下去的勇氣,未來仍然可期,與各位程序編程君共勉!
版權聲明:本文為博主原創(chuàng)文章,遵循相關版權協(xié)議,如若轉載或者分享請附上原文出處鏈接和鏈接來源。