StampedLock源碼分析

1、簡介

       StampedLock是JUC併發包裏面JDK1.8版本新增的一個鎖,該鎖提供了三種模式的讀寫控制,當調用獲取鎖的系列函數的時候,會返回一個long 型的變量,該變量被稱爲戳記(stamp),這個戳記表明了鎖的狀態。 咱們知道「讀寫鎖容許多個線程同時讀共享變量,適用於讀多寫少的場景」。那在讀多寫少的場景中,StampedLock 的性能就比讀寫鎖還要好。ReadWriteLock 支持兩種模式:一種是讀鎖,一種是寫鎖。而 StampedLock 支持三種模式,分別是: 寫鎖、悲觀讀鎖和樂觀讀。其中,寫鎖、悲觀讀鎖的語義和 ReadWriteLock 的寫鎖、讀鎖的語義很是相似,容許多個線程同時獲取悲觀讀鎖,可是隻容許一個線程獲取寫鎖,寫鎖和悲觀讀鎖是互斥的。不一樣的是:StampedLock 裏的寫鎖和悲觀讀鎖加鎖成功以後,都會返回一個 stamp;而後解鎖的時候,須要傳入這個 stamp。 try系列獲取鎖的函數,當獲取鎖失敗後會返回爲0的stamp值。當調用釋放鎖和轉換鎖的方法時候須要傳入獲取鎖時候返回的stamp值。 StampedLock的內部實現是基於CLH鎖的,CLH鎖原理:鎖維護着一個等待線程隊列,全部申請鎖且失敗的線程都記錄在隊列。一個節點表明一個線程,保存着一個標記位locked,用以判斷當前線程是否已經釋放鎖。當一個線程試圖獲取鎖時,從隊列尾節點做爲前序節點,循環判斷全部的前序節點是否已經成功釋放鎖。 它的核心思想在於,在樂觀讀的時候若是發生了寫,應該經過重試的方式來獲取新的值,而不該該阻塞寫操做。這種模式也就是典型的無鎖編程思想,和CAS自旋的思想同樣。這種操做方式決定了StampedLock在讀線程很是多而寫線程很是少的場景下很是適用,同時還避免了寫飢餓狀況的發生。而且StampedLock不支持可重入,而且不支持Condition, 以下圖所示(下圖借鑑網上 ):

2、屬性

//處理器數量
private static final int NCPU = Runtime.getRuntime().availableProcessors();
//在當前節點加入隊列前,若是隊列頭尾節點相等,即屬性whead和wtail相等,先讓其自旋必定的大小,自旋的值
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
//在阻塞當前線程前,若是隊列頭尾節點相等,即屬性whead和wtail相等,先讓其自旋必定的大小,自旋的值
private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
//HEAD_SPINS的最大值
private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
//讀鎖大小溢出時,超過126,線程自增的隨機數&上OVERFLOW_YIELD_RATE時會yeild,下面具體實現中會解釋道
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
//讀鎖最大的bit位
private static final int LG_READERS = 7;
//獲取悲觀讀成功時,state增長的值
private static final long RUNIT = 1L;
//寫鎖獲取成功,state增長的值,寫鎖標誌位(10000000)128
private static final long WBIT  = 1L << LG_READERS;
//在獲取當前讀鎖的個數,判斷當前stampedLock是屬於讀鎖的狀態,127
private static final long RBITS = WBIT - 1L;
//最大的讀鎖大小,126
private static final long RFULL = RBITS - 1L;
//包含讀鎖標誌位和寫鎖標誌位和起來,在獲取鎖和釋放鎖中使用,好比用於判斷state是否處於讀鎖仍是寫鎖,仍是無鎖狀態
private static final long ABITS = RBITS | WBIT;
//用於在樂觀鎖和釋放鎖使用
private static final long SBITS = ~RBITS; // note overlap with ABITS
//StampedLock初始化,state的初始值100000000,256
private static final long ORIGIN = WBIT << 1;
//若是當前線程被中斷,獲取讀寫鎖時,返回的值
private static final long INTERRUPTED = 1L;
//節點的等待狀態
private static final int WAITING   = -1;
//節點的取消狀態
private static final int CANCELLED =  1;
//節點屬於讀模式
private static final int RMODE = 0;
//節點屬於寫模式
private static final int WMODE = 1;
//stampedLock隊列中的頭節點
private transient volatile WNode whead;
//stampedLock隊列中的尾節點
private transient volatile WNode wtail;
//讀鎖的視圖,不可重入,而且不支持condition
transient ReadLockView readLockView;
//寫鎖的視圖,不可重入而且不支持condition
transient WriteLockView writeLockView;
//讀寫鎖的視圖
transient ReadWriteLockView readWriteLockView;
//stampedLock的狀態,用於判斷當前stampedLock是屬於讀鎖仍是寫鎖仍是樂觀鎖
private transient volatile long state;
//讀鎖溢出時,記錄額外的讀鎖大小private transient int readerOverflow;
//UnSafe的使用,若是不清楚的話,能夠看我分享的美團的UnSafe介紹
private static final sun.misc.Unsafe U;
//屬性state的偏移量,定義成靜態的緣由是全部的實例的內存佈局是同樣的,偏移量大小都是相等的
private static final long STATE;
//屬性whead的偏移量
private static final long WHEAD;
//屬性wtail的偏移量
private static final long WTAIL;
//內部類WNode的next屬性偏移量
private static final long WNEXT;
//內部類WNode的status的屬性偏移量
private static final long WSTATUS;
//內部類WNode的cowait屬性偏移量,讀模式的節點隊列
private static final long WCOWAIT;
//Thread類中的parkBlocker屬性偏移量,記錄當前線程被那個對象阻塞起來
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);    }}複製代碼

3、構造函數

//state被初始化爲256,寫鎖標誌位128,讀鎖位
public StampedLock() {    state = ORIGIN;}複製代碼

4、內部類

//等待節點類
static final class WNode {
    //前驅節點 
    volatile WNode prev;
    //當前節點的下一個節點 
    volatile WNode next;
    //等待的讀模式節點 
    volatile WNode cowait;    // list of linked readers
    //節點對應的線程 
     volatile Thread thread;   // non-null while possibly parked
    //節點的狀態 
    volatile int status;      // 0, WAITING, or CANCELLED
    //當前節點是處於讀鎖模式仍是寫鎖模式 
    final int mode;           // RMODE or WMODE
    //構造函數,傳入讀寫鎖模式和前驅節點 
     WNode(int m, WNode p) { mode = m; prev = p; }
}


//讀鎖視圖
final class ReadLockView implements Lock {    
    public void lock() {
         //調用StampedLock的readLock方法,下面會介紹 
         readLock(); 
    }    
    public void lockInterruptibly() throws InterruptedException {
        //調用StampedLock的readLockInterruptibly方法,下面會介紹 
         readLockInterruptibly();    
    }    
    public boolean tryLock() { 
         //調用StampedLock的tryReadLock方法,下面會介紹
         return tryReadLock() != 0L; 
    }    
    
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //調用StampedLock的tryReadLock(time, unit)方法 
        return tryReadLock(time, unit) != 0L;    
    }    
    public void unlock() {
        //調用StampedLock的unstampedUnlockRead方法
        unstampedUnlockRead(); 
    }    
    //不支持Condition,和ReadWriteLock的區別
    public Condition newCondition() {        
        throw new UnsupportedOperationException();    
    }
}
   

//寫鎖視圖
final class WriteLockView implements Lock {    
    public void lock() { 
       //調用StampedLock的writeLock方法,下面會詳細介紹
       writeLock(); 
    }    
    public void lockInterruptibly() throws InterruptedException {
        //調用StampedLock的writeLockInterruptibly方法,下面會詳細介紹 
        writeLockInterruptibly();    
   }    
   public boolean tryLock() {
        //調用StampedLock的tryWriteLock方法,下面會詳細介紹
        return tryWriteLock() != 0L; 
   }    
   public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {        //調用StampedLock的tryWriteLock(time, unit)方法,下面會詳細介紹
        return tryWriteLock(time, unit) != 0L;    
   }    
    public void unlock() { 
        //調用StampedLock的unstampedUnlockWrite方法 
        unstampedUnlockWrite(); 
    }    
    //不支持Condition
    public Condition newCondition() {        
        throw new UnsupportedOperationException();    
     }
}

//讀寫鎖視圖
final class ReadWriteLockView implements ReadWriteLock {    
    //獲取讀鎖視圖,若是讀鎖視圖未初始化,初始化讀鎖視圖
    public Lock readLock() { 
        return asReadLock();//return ((v = readLockView) != null ? v : (readLockView = new ReadLockView())); 
    }
    //獲取寫鎖視圖,若是寫鎖視圖未初始化,初始化寫鎖視圖 
    public Lock writeLock() { 
       return asWriteLock(); //((v = writeLockView) != null ? v : (writeLockView = new WriteLockView())); 
    }
}複製代碼

5、寫鎖的獲取、釋放

  1. 寫鎖的獲取

    //獲取排他鎖,若是不能立刻獲取到,必要的時候會將其阻塞,writeLock方法不支持中斷操做
    public long writeLock() {    
        long s, next;  // bypass acquireWrite in fully unlocked case only 
        //若是當前StampedLock的狀態state爲初始狀態即256(100000000),&上255等於0,代表當前屬於無鎖狀態,寫鎖能夠獲取成功,因爲是對共享變量的操做,使用cas,進行變量的更新。不然&255不等於0代表當前處於有鎖狀態,調用acquireWrite方法,下面會介紹 
        return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? next : acquireWrite(false, 0L));
    }
    
    //非阻塞的獲取寫鎖,若是獲取寫鎖失敗返回stamp爲0,若是當前處於無鎖狀態而且cas更新StampedLock的state屬性成功,返回s+WBIT的stamp
    public long tryWriteLock() {
        long s, next;
        return ((((s = state) & ABITS) == 0L &&
                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
                next : 0L);
    }
    
    //超時的獲取寫鎖,而且支持中斷操做
    public long tryWriteLock(long time, TimeUnit unit) throws InterruptedException {
        //將其時間轉成納秒 
        long nanos = unit.toNanos(time);
        if (!Thread.interrupted()) {
            long next, deadline;
            //先調用上面介紹的非阻塞tryWriteLock獲取寫鎖,若是能加鎖成功直接返回
            if ((next = tryWriteLock()) != 0L)
                return next;
            //若是時間小於等於0直接返回,加寫鎖失敗 
            if (nanos <= 0L)
                return 0L;
            //System.nanoTime()可能返回負,若是和傳入的時間相加等於0,deadline等於1
            if ((deadline = System.nanoTime() + nanos) == 0L)
                deadline = 1L;
            //調用下面介紹的acquireWrite方法,若是超時,返回的結果不是中斷的值INTERRUPTED,加鎖成功,返回對應的Stamp值(state+WBIT)
            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
                return next;
        }
        //不然拋出中斷異常
        throw new InterruptedException();
    }
    
    //中斷的獲取寫鎖,獲取不到寫鎖拋出中斷異常
    public long writeLockInterruptibly() throws InterruptedException {
            long next;
            //當前線程沒有被中斷,而且調用acquireWrite方法不是返回INTERRUPTED中斷標誌位,不然拋出中斷異常,若是返回的標誌位是0,也表示獲取寫鎖失敗 
            if (!Thread.interrupted() &&
                (next = acquireWrite(true, 0L)) != INTERRUPTED)
                return next;
            //拋出中斷異常
            throw new InterruptedException();
    }
    
    
    private long acquireWrite(boolean interruptible, long deadline) {    
        WNode node = null, p;    
        //將其當前節點,做爲隊列的尾節點,若是當前隊列頭結點和尾節點相等,而且StampedLock的狀態屬性state爲WBIT,先自旋一段時間,若是自旋仍是沒有獲取寫鎖成功,再將其做爲隊列的尾節點加入
        for (int spins = -1;;) { // spin while enqueuing 
              long m, s, ns;
              //若是當前state等於256,屬於無鎖狀態,直接加寫鎖,若是加鎖成功直接返回 
              if ((m = (s = state) & ABITS) == 0L) {            
                   if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))                
                       return ns;        
              } 
              //若是spins小於0,而且當前的StampedLock屬於寫鎖狀態,以及頭尾節點相等,spins賦值SPINS,讓其當前線程自旋一段時間獲取寫鎖 
              else if (spins < 0)            
                   spins = (m == WBIT && wtail == whead) ? SPINS : 0; 
              else if (spins > 0) {
                   // LockSupport.nextSecondarySeed() >= 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;        
              }    
      }
       
      //阻塞當前線程,再阻塞當前線程以前,若是頭節點和尾節點相等,讓其自旋一段時間獲取寫鎖。若是頭結點不爲空,釋放頭節點的cowait隊列 
      for (int spins = -1;;) {
                WNode h, np, pp; int ps;
                //頭尾節點相等
                if ((h = whead) == p) {
                    //設置初始自旋的值
                    if (spins < 0)
                        spins = HEAD_SPINS;
                    //若是spins仍是小於MAX_HEAD_SPINS,將其擴大2倍
                    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;
                            }
                        }
                        //LockSupport.nextSecondarySeed() >= 0永真,k作自減操做 
                        else if (LockSupport.nextSecondarySeed() >= 0 &&
                                 --k <= 0)
                            break;
                    }
                }
                //若是頭結點不爲空
                else if (h != null) {
                    WNode c; Thread w;
                    //若是頭結點的cowait隊列(RMODE的節點)不爲空,喚醒cowait隊列
                    while ((c = h.cowait) != null) {
                        //cowait節點和對應的節點都不爲空喚醒其線程,循環的喚醒cowait節點隊列中Thread不爲空的線程
                        if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
                            (w = c.thread) != null)
                            //UnSafe的使用不了解的,能夠看個人分享
                            U.unpark(w);
                    }
                }
                //若是頭結點不變
                if (whead == h) {
                    //若是當前節點的前驅節點和尾節點不一致,將p設置爲當前節點的前驅節點,可使節點往頭節點移動,若是當前節點的前驅節點已是頭結點
                    if ((np = node.prev) != p) {
                        if (np != null)
                            //將其p設置爲當前節點的前驅節點
                            (p = np).next = node;
                    }
                    //若是當前節點的前驅節點狀態爲0,將其前驅節點設置爲等待狀態
                    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,阻塞直到UnSafe.unpark喚醒
                        if (deadline == 0L)
                            time = 0L;
                        //若是時間已經超時,取消當前的等待節點
                        else if ((time = deadline - System.nanoTime()) <= 0L)
                            //取消節點的cancelWaiter方法下面會介紹
                            return cancelWaiter(node, node, false);
                        //獲取當前線程
                        Thread wt = Thread.currentThread();
                        //設置線程Thread的parkblocker屬性,表示當前線程被誰阻塞,用於監控線程使用
                        U.putObject(wt, PARKBLOCKER, this);
                        //將其當前線程設置爲當前節點
                        node.thread = wt;
                        //當前節點的前驅節點爲等待狀態,而且隊列的頭節點和尾節點不相等或者StampedLock當前狀態爲有鎖狀態,隊列頭節點不變,當前節點的前驅節點不變,阻塞當前線程
                        if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
                            whead == h && node.prev == p)
                            //模擬阻塞當前線程,只有調用UnSafe.unpark()喚醒,若是time不等於0,時間到也會自動喚醒
                            U.park(false, time);
                        //當前節點的線程置爲空 
                        node.thread = null;
                        //當前線程的監控對象也置爲空
                        U.putObject(wt, PARKBLOCKER, null);
                        //若是傳入的參數interruptible爲true,而且當前線程中斷,取消當前節點
                        if (interruptible && Thread.interrupted())
                            //取消節點的cancelWaiter方法下面會介紹
                            return cancelWaiter(node, node, true);
                    }
                }
            }
    
    
    //取消等待節點
    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
           //node和group爲同一節點,要取消的節點,都不爲空時 
           if (node != null && group != null) {
                Thread w;
                //將其當前節點的狀態設置爲取消狀態
                node.status = CANCELLED;
                //若是當前要取消節點的cowait隊列不爲空,將其cowait隊列中取消的節點去除
                for (WNode p = group, q; (q = p.cowait) != null;) {
                    if (q.status == CANCELLED) {
                        U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
                        p = group; 
                    }
                    else
                        p = q;
                }
                
                //group和node爲同一節點
                if (group == node) {
                    //喚醒狀態沒有取消的cowait隊列中的節點
                    for (WNode r = group.cowait; r != null; r = r.cowait) {
                        if ((w = r.thread) != null)
                            U.unpark(w); 
                    }
                    //將其當前取消節點的前驅節點的下一個節點設置爲當前取消節點的next節點
                    for (WNode pred = node.prev; pred != null; ) { // unsplice
                        WNode succ, pp;
                        //若是當前取消節點的下一個節點爲空或者是取消狀態,從尾節點開始,尋找有效的節點 
                        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;     
                            //若是當前取消節點的next節點和從尾節點尋找的節點相等,或者將其尋找的節點q設置爲下一個節點成功
                            if (succ == q ||   
                                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
                            //將其前驅節點的下一節點設置爲當前取消節點的next有效節點
                            U.compareAndSwapObject(pred, WNEXT, node, succ);
                        //喚醒當前取消節點的下一節點,觀察其新的前驅節點 
                        if (succ != null && (w = succ.thread) != null) {
                            succ.thread = null;
                            U.unpark(w);       
                        }
                        //若是當前取消節點的前驅節點狀態不是取消狀態,或者其前驅節點的前驅節點爲空,直接退出循環 
                        if (pred.status != CANCELLED || (pp = pred.prev) == null)
                            break;
                        //從新設置當前取消節點的前驅節點
                        node.prev = pp;
                        //從新設置pp的下一節點 
                        U.compareAndSwapObject(pp, WNEXT, pred, succ);
                        //將其前驅節點設置爲pp,從新循環
                        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) {
                    //頭節點的下一有效節點不爲空,而且頭節點的狀態爲0,而且當前StampedLock的不爲寫鎖狀態,而且頭節點的下一節點爲讀模式,喚醒頭結點的下一節點
                    if (q != null && h.status == 0 &&
                        ((s = state) & ABITS) != WBIT && // waiter is eligible
                        (s == 0L || q.mode == RMODE))
                        //喚醒頭結點的下一有效節點,下面會介紹release方法
                        release(h);
                    break;
                }
            }
            //若是當前線程被中斷或者傳入進來的interrupted爲true,直接返回中斷標誌位,不然返回0 
            return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
        }
    }
    
    
    //喚醒頭結點的下一有效節點
    private void release(WNode h) {
            //頭結點不爲空
            if (h != null) {
                WNode q; Thread w;
                //若是頭結點的狀態爲等待狀態,將其狀態設置爲0
                U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
                //從尾節點開始,到頭節點結束,尋找狀態爲等待或者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);
            }
    }
      複製代碼
  2.  寫鎖的釋放

    //根據傳入的stamp釋放寫鎖
    public void unlockWrite(long stamp) {
            WNode h;
            //若是當前StampedLock的鎖狀態state和傳入進來的stamp不匹配或者傳入進來的不是寫鎖標誌位,往外拋出IllegalMonitorStateException異常
            if (state != stamp || (stamp & WBIT) == 0L)
                throw new IllegalMonitorStateException();
            /** * 釋放寫鎖爲何不直接減去stamp,再加上ORIGIN,而是(stamp += WBIT) == 0L ? ORIGIN : stamp來釋放寫鎖,位操做表示以下: * stamp += WBIT 即0010 0000 0000 = 0001 1000 0000 + 0000 1000 0000 * 這一步操做是重點!!!寫鎖的釋放並非像ReentrantReadWriteLock同樣+1而後-1,而是經過再次加0000 1000 0000來使高位每次都產生變化,爲何要這樣作?直接減掉0000 1000 0000不就能夠了嗎?這就是爲了後面樂觀鎖作鋪墊,讓每次寫鎖都留下痕跡。 * 你們知道cas ABA的問題,字母A變化爲B能看到變化,若是在一段時間內從A變到B而後又變到A,在內存中自會顯示A,而不能記錄變化的過程。在StampedLock中就是經過每次對高位加0000 1000 0000來達到記錄寫鎖操做的過程,能夠經過下面的步驟理解: * * 第一次獲取寫鎖: * 0001 0000 0000 + 0000 1000 0000 = 0001 1000 0000 * 第一次釋放寫鎖: * 0001 1000 0000 + 0000 1000 0000 = 0010 0000 0000 * 第二次獲取寫鎖: * 0010 0000 0000 + 0000 1000 0000 = 0010 1000 0000 * 第二次釋放寫鎖: * 0010 1000 0000 + 0000 1000 0000 = 0011 0000 0000 * 第n次獲取寫鎖: * 1110 0000 0000 + 0000 1000 0000 = 1110 1000 0000 * 第n次釋放寫鎖: * 1110 1000 0000 + 0000 1000 0000 = 1111 0000 0000 * * 能夠看到第8位在獲取和釋放寫鎖時會產生變化,也就是說第8位是用來表示寫鎖狀態的,前7位是用來表示讀鎖狀態的,8位以後是用來表示寫鎖的獲取次數的。這樣就有效的解決了ABA問題,留下了每次寫鎖的記錄,也爲後面樂觀鎖檢查變化提供了基礎。 */
            state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
            //頭結點不爲空,而且頭結點的狀態不爲0
            if ((h = whead) != null && h.status != 0)
                //看上面release方法的介紹 
                release(h);
    }
    
    //無需傳入stamp釋放寫鎖
    public boolean tryUnlockWrite() {
            long s; WNode h;
            //若是當前StampedLock的鎖狀態state不是寫鎖狀態,直接返回釋放失敗
            if (((s = state) & WBIT) != 0L) {
                //看上面解釋 釋放寫鎖爲何不直接減去stamp,再加上ORIGIN 
                state = (s += WBIT) == 0L ? ORIGIN : s;
                //頭結點不爲空,而且頭結點的狀態不爲0 
                if ((h = whead) != null && h.status != 0)
                    //看上面release方法的介紹
                    release(h);
                return true;
            }
            return false;
    }
    
    //讀寫鎖均可以釋放,若是鎖狀態匹配給定的郵票,釋放鎖的相應模式,StampedLock的state處於樂觀讀時,不能調用此方法,由於樂觀讀不是鎖
    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;
                //若是當前StampedLock的狀態爲寫模式
                else if (m == WBIT) {
                    //傳入進來的stamp不是寫模式,直接退出,拋出異常
                    if (a != m)
                        break;
                    //不然的話釋放寫鎖,看上面解釋爲何不是直接減去WBIT,再加上ORIGIN
                    state = (s += WBIT) == 0L ? ORIGIN : s;
                    //頭結點不爲空,而且頭結點的狀態不爲0 
                    if ((h = whead) != null && h.status != 0)
                        //看看上面release方法的介紹 
                        release(h);
                    return;
                }
                //若是傳入進來的狀態是無鎖模式,或者是樂觀讀模式,直接退出,拋出異常
                else if (a == 0L || a >= WBIT)
                    break;
                //若是處於讀鎖模式,而且讀鎖沒有溢出
                else if (m < RFULL) {
                    //cas操做使StampedLock的state狀態減1,釋放一個讀鎖,失敗時,從新循環
                    if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                        //若是當前讀鎖只有一個,而且頭結點不爲空,而且頭結點的狀態不爲0
                        if (m == RUNIT && (h = whead) != null && h.status != 0)
                            //看上面的release方法介紹
                            release(h);
                        return;
                    }
                }
                //tryDecReaderOverflow方法看下面介紹
                else if (tryDecReaderOverflow(s) != 0L)
                    return;
            }
            //拋出異常
            throw new IllegalMonitorStateException();
    }
    
    private long tryDecReaderOverflow(long s) {
            //若是當前StampedLock的state的讀模式已滿,s&ABITS爲126
            if ((s & ABITS) == RFULL) {
                //先將其state設置爲127
                if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
                    int r; long next;
                    //若是當前readerOverflow(記錄溢出的讀鎖個數)大於0
                    if ((r = readerOverflow) > 0) {
                        //readerOverflow作減1操做
                        readerOverflow = r - 1;
                        //將其next設置爲原來的state
                        next = s;
                    }
                    else
                        //不然的話,將其當前的state作減1操做 
                        next = s - RUNIT;
                     //將其state設置爲next
                     state = next;
                     return next;
                }
            }
            //若是當前線程隨機數&上7要是等於0,線程讓步
            else if ((LockSupport.nextSecondarySeed() &
                      OVERFLOW_YIELD_RATE) == 0)
                Thread.yield();
            return 0L;
    }
    複製代碼

6、讀鎖的獲取和釋放

  1. 讀鎖的獲取

    //獲取非排它性鎖,讀鎖,若是獲取不到讀鎖,阻塞直到可用,而且該方法不支持中斷操做
    public long readLock() {
            long s = state, next;
            //若是頭結點和尾節點相等(由於若是StampedLock只有非排他性鎖,讀鎖或者樂觀讀,隊列中只存在一個相同的節點),而且目前的讀鎖個數小於126,而後cas進行state的加1操做,若是獲取成功直接退出,不然執行acquireRead方法
            return ((whead == wtail && (s & ABITS) < RFULL &&
                     U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
                    next : acquireRead(false, 0L));//acquireRead方法會在下面進行介紹
    }
    
    //非阻塞的獲取非排他性鎖,讀鎖,若是獲取成功直接返回stamp的long值,不然返回0
    public long tryReadLock() {
            for (;;) {
                long s, m, next;
                //若是目前StampedLock的狀態爲寫鎖狀態,直接返回0,獲取讀鎖失敗
                if ((m = (s = state) & ABITS) == WBIT)
                    return 0L;
                //若是當前狀態處於讀鎖狀態,而且讀鎖沒有溢出 
                else if (m < RFULL) {
                    //使用cas操做使state進行加1操做,若是cas成功,直接返回next,不然從新進行循環 
                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
                        return next;
                }
                //若是讀鎖溢出,調用下面介紹的tryIncReaderOverflow方法,若是操做成功,直接返回,不然從新進行循環操做
                else if ((next = tryIncReaderOverflow(s)) != 0L)
                    return next;
            }
    }
    
    //記錄溢出讀鎖的個數
    private long tryIncReaderOverflow(long s) {
            //若是state&上255等於126 
            if ((s & ABITS) == RFULL) {
                // 使用cas操做將其state設置爲127
                if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
                    //將其記錄額外溢出的讀鎖個數進行加1操做
                    ++readerOverflow;
                    //將其state從新置爲原來的值
                    state = s;
                    //返回傳進來的值
                    return s;
                }
            }
            //若是當前線程的隨機數增長操做&上7等於0,將其線程進行讓步操做
            else if ((LockSupport.nextSecondarySeed() &
                      OVERFLOW_YIELD_RATE) == 0)
                Thread.yield();
            //不然直接返回0失敗
            return 0L;
    }
    
    //超時的獲取非排他性鎖,讀鎖,而且支持中斷操做
    public long tryReadLock(long time, TimeUnit unit) throws InterruptedException {
            long s, m, next, deadline;
            long nanos = unit.toNanos(time);
            //若是當前線程沒有被中斷
            if (!Thread.interrupted()) {
                //而且當前StampedLock的狀態不處於寫鎖狀態 
                if ((m = (s = state) & ABITS) != WBIT) {
                    //而且讀鎖沒有溢出,使用cas操做state加1,若是成功直接返回
                    if (m < RFULL) {
                        if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
                            return next;
                    }
                    //若是讀鎖溢出,調用tryIncReaderOverflow方法,看上面的介紹 
                    else if ((next = tryIncReaderOverflow(s)) != 0L)
                        return next;
                }
                //若是超時時間小於等於0,直接返回0,獲取讀鎖失敗
                if (nanos <= 0L)
                    return 0L;
                //若是System.nanoTime加上nanos等於0,將其deadline時間設置爲1,由於System.nanoTime可能爲負數
                if ((deadline = System.nanoTime() + nanos) == 0L)
                    deadline = 1L;
                //若是調用acquireRead方法返回不是中斷的標誌位INTERRUPTED,直接返回,next不等於0獲取讀鎖成功,不然獲取讀鎖失敗
                if ((next = acquireRead(true, deadline)) != INTERRUPTED)
                    return next;
            }
       //拋出中斷異常 throw new InterruptedException();
    }
    
    //獲取非排它性鎖,讀鎖,若是獲取不到讀鎖,阻塞直到可用,而且該方法支持中斷操做 
    public long readLockInterruptibly() throws InterruptedException {
            long next;
            //若是當前線程沒有被中斷,而且調用acquireRead方法沒有返回被中斷的標誌位INTERRUPTED回來,直接退出,next值不等於0獲取讀鎖成功
            if (!Thread.interrupted() &&
                (next = acquireRead(true, 0L)) != INTERRUPTED)
                return next;
            //拋出被中斷異常
            throw new InterruptedException();
    }    
    
    //支持中斷和超時的獲取讀鎖,這個方法主要作的事情包括,若是頭結點和尾節點相等,自旋一段時間,獲取讀鎖,不然的話,若是隊列爲空,構建頭尾節點,若是當前隊列頭節點和尾節點相等或者是當前StampedLock處於寫鎖狀態,初始化當前節點,將其設置成尾節點。若是頭結點的cwait隊列不爲空,喚醒cwait隊列的線程,將其當前節點阻塞,直到被喚醒可用
    private long acquireRead(boolean interruptible, long deadline) {
            WNode node = null, p;
            //若是頭結點和尾節點相等,先讓其線程自旋一段時間,若是隊列爲空初始化隊列,生成頭結點和尾節點。若是自旋操做沒有獲取到鎖,而且頭結點和尾節點相等,或者當前stampedLock的狀態爲寫鎖狀態,將其當前節點加入隊列中,若是加入當前隊列失敗,或者頭結點和尾節點不相等,或者當前處於讀鎖狀態,將其加入尾節點的cwait中,若是頭結點的cwait節點不爲空,而且線程也不爲空,喚醒其cwait隊列,阻塞當前節點
            for (int spins = -1;;) {
                WNode h;
                //若是頭尾節點相等,先讓其自旋一段時間
                if ((h = whead) == (p = wtail)) {
                    for (long m, s, ns;;) {
                        //若是當前StampedLock的state狀態爲讀鎖狀態,而且讀鎖沒有溢出,使用cas操做state進行加1操做 
                        if ((m = (s = state) & ABITS) < RFULL ?
                            U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
                            (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))//不然當前處於讀鎖,而且讀鎖溢出,調用tryIncReaderOverflow方法,看上面的此方法的介紹
                            return ns;
                        //若是當前狀態處於寫鎖狀態,或者大於寫鎖的狀態
                        else if (m >= WBIT) {
                            //spins大於0,讓其作自減操做
                            if (spins > 0) {
                                if (LockSupport.nextSecondarySeed() >= 0)
                                    --spins;
                            }
                            else {
                                //若是自旋操做spins減到0
                                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);
                    //使用cas構造隊列的頭結點,若是成功,將其尾節點設置爲頭結點
                    if (U.compareAndSwapObject(this, WHEAD, null, hd))
                        wtail = hd;
                }
                //若是當前節點爲空,構造當前節點
                else if (node == null)
                    node = new WNode(RMODE, p);
                //若是頭結點和尾節點相等,或者當前StampedLock的state狀態不爲讀鎖狀態
                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;
                    }
                }
                //將其當前節點加入尾節點的cowait隊列中,若是失敗,將其當前節點的cowait置爲null
                else if (!U.compareAndSwapObject(p, WCOWAIT,
                                                 node.cowait = p.cowait, node))
                    node.cowait = null;
                //若是當前隊列不爲空,當前節點不爲空,而且頭結點和尾節點不相等,而且當前StampedLock的狀態爲讀鎖狀態,而且當前節點cas加入尾節點的cowait隊列中失敗
                else {
                    for (;;) {
                        WNode pp, c; Thread w;
                        //若是頭結點的cowait隊列不爲空,而且其線程也不爲null,將其cowait隊列喚醒
                        if ((h = whead) != null && (c = h.cowait) != null &&
                            U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
                            (w = c.thread) != null) // help release
                            //喚醒cowait隊列中的節點線程
                            U.unpark(w);
                        //若是當前頭結點爲尾節點的前驅節點,或者頭尾節點相等,或者尾節點的前驅節點爲空
                        if (h == (pp = p.prev) || h == p || pp == null) {
                            long m, s, ns;
                            do {
                                //判斷當前狀態是否處於讀鎖狀態,若是是,而且讀鎖沒有溢出,state進行cas加1操做
                                if ((m = (s = state) & ABITS) < RFULL ?
                                    U.compareAndSwapLong(this, STATE, s,
                                                         ns = s + RUNIT) :
                                    (m < WBIT &&
                                     (ns = tryIncReaderOverflow(s)) != 0L))//不然進行溢出操做,看上面tryIncReaderOverflow方法介紹
                                    return ns;
                            } while (m < WBIT);//當前StampedLock的state狀態不是寫模式,才能進行循環操做
                        }
                        //若是頭結點沒有改變,而且尾節點的前驅節點不變
                        if (whead == h && p.prev == pp) {
                            long time;
                            //若是尾節點的前驅節點爲空,或者頭尾節點相等,或者尾節點的狀態爲取消
                            if (pp == null || h == p || p.status > 0) {
                                //將其當前節點設置爲空,退出循環
                                node = null; // throw away
                                break;
                            }
                            //若是超時時間爲0,會一直阻塞,直到調用UnSafe的unpark方法
                            if (deadline == 0L)
                                time = 0L;
                            //若是傳入的超時時間已通過期,將當前節點取消,看上面cancelWaiter方法的介紹
                            else if ((time = deadline - System.nanoTime()) <= 0L)
                                return cancelWaiter(node, p, false);
                            //獲取當前線程 
                            Thread wt = Thread.currentThread();
                            //設置當前線程被誰阻塞的監控對象
                            U.putObject(wt, PARKBLOCKER, this);
                            //將其當前節點的線程設置爲當前線程
                            node.thread = wt;
                            //若是頭節點和尾節點的前驅節點不相等,或者當前StampedLock的state狀態爲寫鎖,而且頭結點不變,尾節點的前驅節點不變
                            if ((h != pp || (state & ABITS) == WBIT) &&
                                whead == h && p.prev == pp)
                                //調用UnSafe的park來進行阻塞當前線程 
                                U.park(false, time);
                            //將其當前節點的線程置爲空
                            node.thread = null;
                            //將其當前線程的監控對象置爲空
                            U.putObject(wt, PARKBLOCKER, null);
                            //若是傳入進來的interruptible是要求中斷的,而且當前線程被中斷
                            if (interruptible && Thread.interrupted())
                                //看上面cancelWaiter方法的介紹 
                                return cancelWaiter(node, p, true);
                        }
                    }
                }
            }
            //阻塞當前線程,再阻塞當前線程以前,若是頭節點和尾節點相等,讓其自旋一段時間獲取寫鎖。若是頭結點不爲空,釋放頭節點的cowait隊列 
            for (int spins = -1;;) {
                WNode h, np, pp; int ps;
                //若是頭節點和尾節點相等
                if ((h = whead) == p) {
                    //自旋的初始值 
                    if (spins < 0)
                        spins = HEAD_SPINS;
                    //若是spins小於MAX_HEAD_SPINS
                    else if (spins < MAX_HEAD_SPINS)
                        //將其spins進行擴大兩倍
                        spins <<= 1;
                    //自旋一段時間獲取讀鎖
                    for (int k = spins;;) { // spin at head
                        long m, s, ns;
                        //若是當前狀態爲無鎖或者讀鎖模式 
                        if ((m = (s = state) & ABITS) < RFULL ?
                            //state進行cas加1操做
                            U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
                            //若是當前state狀態爲讀鎖狀態,而且讀鎖溢出,使用tryIncReaderOverflows方法進行溢出的讀鎖數累加
                            (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
                            WNode c; Thread w;
                            //將其節點設置爲頭結點
                            whead = node;
                            //將其當前節點的前驅節點設置爲空
                            node.prev = null;
                            //若是當前節點的cowait隊列不爲空,循環的喚醒cowait隊列中,線程不爲空的線程
                            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;
                    //頭結點的cowait隊列不爲空,循環的喚醒的cowait隊列中,線程不爲空的節點的線程
                    while ((c = h.cowait) != null) {
                        if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
                            (w = c.thread) != null)
                            //使用UnSafe進行喚醒
                            U.unpark(w);
                    }
                }
                //若是頭結點沒改變
                if (whead == h) {
                    //若是當前節點的前驅節點不等於尾節點
                    if ((np = node.prev) != p) {
                        //當前節點的前驅節點不爲空 
                        if (np != null)
                            //將其p設置爲當前節點的前驅節點,若是前面的節點已經被喚醒,將p設置爲當前節點的前驅節點,有可能其前驅節點就是頭結點,從新進行循環操做
                            (p = np).next = node;   // stale
                    }
                    //若是當前節點的前驅節點的狀態爲0 
                    else if ((ps = p.status) == 0)
                        //將其當前節點的狀態使用cas操做將其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,永久阻塞,直到調用UnSafe的unpark()方法
                        if (deadline == 0L)
                            time = 0L;
                        //若是當前時間已通過期,取消當前節點
                        else if ((time = deadline - System.nanoTime()) <= 0L)
                            //cancelWaiter方法能夠看上面對此方法的介紹
                            return cancelWaiter(node, node, false);
                        //獲取當前線程
                        Thread wt = Thread.currentThread();
                        //將其當前線程的監控對象設置爲當前StampedLock,監控此線程被那個對象阻塞
                        U.putObject(wt, PARKBLOCKER, this);
                        //將其當前線程設置爲當前隊列中的線程
                        node.thread = wt;
                        //若是當前節點的前驅節點爲等待狀態,而且頭尾節點不相等或者當前StampedLock的狀態爲寫鎖狀態,而且頭結點不變,當前節點的前驅節點不變
                        if (p.status < 0 &&
                            (p != h || (state & ABITS) == WBIT) &&
                            whead == h && node.prev == p)
                            //調用UnSafe的park方法阻塞當前線程
                            U.park(false, time);
                        //將其當前節點對應的線程置爲空
                        node.thread = null;
                        //將其當前線程的監控對象置爲空
                        U.putObject(wt, PARKBLOCKER, null);
                        //若是傳入進來的參數interruptible爲true,而且當前線程被中斷 
                        if (interruptible && Thread.interrupted())
                            //取消當前節點,cancelWaiter方法能夠看上面對此方法的介紹
                            return cancelWaiter(node, node, true);
                    }
                }
            }
    }
    複製代碼

  2. 讀鎖的釋放

    //傳入stamp進行讀鎖的釋放
    public void unlockRead(long stamp) {
            long s, m; WNode h;
            for (;;) {
                //傳進來的stamp和當前stampedLock的state狀態不一致,或者當前處於樂觀讀、無鎖狀態,或者傳進來的參數是樂觀讀、無鎖的stamp,又或者當前狀態爲寫鎖狀態,拋出非法的鎖狀態異常
                if (((s = state) & SBITS) != (stamp & SBITS) ||
                    (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
                    throw new IllegalMonitorStateException();
                //若是當前StampedLock的state狀態爲讀鎖狀態,而且讀鎖沒有溢出
                if (m < RFULL) {
                    //state使用cas進行減1操做
                    if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                        //若是減一操做成功,而且當前處於無鎖狀態,而且頭結點不爲空,而且頭結點的狀態爲非0狀態
                        if (m == RUNIT && (h = whead) != null && h.status != 0)
                            //能夠看上面對release方法的介紹 
                            release(h);
                        break;
                    }
                }
                //能夠看下面對tryDecReaderOverflow方法的介紹,若是不等於0直接退出,不然從新進行循環
                else if (tryDecReaderOverflow(s) != 0L)
                    break;
            }
    }
    
    //讀鎖溢出進行減操做的方法
    private long tryDecReaderOverflow(long s) {
            // assert (s & ABITS) >= RFULL;
            //若是當前狀態s&上255等於126,當前讀鎖已滿, 
            if ((s & ABITS) == RFULL) {
                //將其當前state狀態設置爲127
                if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
                    int r; long next;
                    //若是設置成功,而且溢出的鎖數目大於0,將其額外的讀鎖數進行減1操做
                    if ((r = readerOverflow) > 0) {
                        readerOverflow = r - 1;
                        //將其next設置爲傳上來的state狀態
                        next = s;
                    }
                    else
                        //若是當前溢出數爲0,將其當前狀態進行減1操做
                        next = s - RUNIT;
                     //將其state從新設置爲next 
                     state = next;
                     return next;
                }
            }
            //若是當前線程的隨機數&上7等於0,當前線程進行讓步
            else if ((LockSupport.nextSecondarySeed() &
                      OVERFLOW_YIELD_RATE) == 0)
                //線程讓步 
                Thread.yield();
            return 0L;
    }
    
    //無需傳入stamp進行釋放讀鎖
    public boolean tryUnlockRead() {
            long s, m; WNode h;
            //若是當前狀態處於讀鎖狀態,而不是樂觀讀狀態,或者無鎖狀態,或者寫鎖狀態
            while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
                //若是當前state處於讀鎖狀態,而且讀鎖沒有溢出
                if (m < RFULL) {
                    //stampedLock狀態state使用cas進行減1操做,若是成功,跳出循環,直接返回
                    if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                        //若是操做成功,而且當前狀態處於無鎖狀態,而且頭結點不爲空,及頭結點的狀態不爲0
                        if (m == RUNIT && (h = whead) != null && h.status != 0)
                            //看上面對release方法的介紹
                            release(h);
                        return true;
                    }
                }
                //若是當前處於讀鎖模式,而且讀鎖溢出,使用上面介紹的tryDecReaderOverflow方法,若是返回非0,直接退出,返回成功,不然從新進行循環
                else if (tryDecReaderOverflow(s) != 0L)
                    return true;
            }
            return false;
    }
    
    複製代碼

7、樂觀讀獲取、校驗

  1. 樂觀讀的獲取

    public long tryOptimisticRead() {
            long s;
            //若是當前state不處於寫模式返回s&SBITS,不然返回0失敗
            return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
    }複製代碼

  2. 樂觀讀的校驗

    public boolean validate(long stamp) {
            //在校驗邏輯以前,會經過Unsafe的loadFence方法加入一個load內存屏障,目的是避免copy變量到工做內存中和StampedLock.validate中鎖狀態校驗運算髮生重排序致使鎖狀態校驗不許確的問題,不清楚的話能夠看下我分享的UnSafe使用的內存屏障介紹
            U.loadFence();
            //若是傳入進來的stamp & SBITS和state & SBITS相等
            return (stamp & SBITS) == (state & SBITS);
    }複製代碼

8、鎖的升級

  1. 升級爲寫鎖

    //升級爲寫鎖
    public long tryConvertToWriteLock(long stamp) {
            long a = stamp & ABITS, m, s, next;
            //若是傳入進來的stamp和當前StampedLock的狀態相同
            while (((s = state) & SBITS) == (stamp & SBITS)) {
                //若是當前處於無鎖狀態,或者樂觀讀狀態
                if ((m = s & ABITS) == 0L) {
                    //傳入進來的stamp不處於無鎖或者樂觀讀狀態,直接退出,升級失敗
                    if (a != 0L)
                        break;
                    //獲取state使用cas進行寫鎖的獲取,若是獲取寫鎖成功直接退出
                    if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
                        return next;
                }
                //若是當前stampedLock處於寫鎖狀態
                else if (m == WBIT) {
                    //傳入進來的stamp不處於寫鎖狀態,直接退出
                    if (a != m)
                        break;
                    //不然直接返回當前處於寫鎖狀態的stamp
                    return stamp;
                }
                //若是當前只有一個讀鎖,當前狀態state使用cas進行減1加WBIT操做,將其讀鎖升級爲寫鎖狀態
                else if (m == RUNIT && a != 0L) {
                    if (U.compareAndSwapLong(this, STATE, s,
                                             next = s - RUNIT + WBIT))
                        return next;
                }
                //不然直接退出
                else
                    break;
            }
            return 0L;
    }複製代碼

  2. 升級爲讀鎖

    public long tryConvertToReadLock(long stamp) {
            long a = stamp & ABITS, m, s, next; WNode h;
            //若是傳入進來的stamp和當前StampedLock的狀態相同
            while (((s = state) & SBITS) == (stamp & SBITS)) {
                //若是當前StampedLock處於無鎖狀態或者樂觀讀狀態
                if ((m = s & ABITS) == 0L) {
                    //若是傳入進來的stamp不處於無鎖或者樂觀讀狀態,直接退出,升級讀鎖失敗
                    if (a != 0L)
                        break;
                    //若是當前StampedLock處於讀鎖、無鎖或者樂觀讀狀態,而且讀鎖數沒有溢出
                    else if (m < RFULL) {
                        //state使用cas操做進行加1操做,若是操做成功直接退出
                        if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
                            return next;
                    }
                    //若是讀鎖溢出,調用tryIncReaderOverflow方法的溢出操做,此方法能夠看上面的介紹,若是返回非0,代表升級讀鎖成功,直接退出
                    else if ((next = tryIncReaderOverflow(s)) != 0L)
                        return next;
                }
                //若是當前StampedLock的state處於寫鎖狀態,若是鎖升級成功,直接返回,不然從新循環
                else if (m == WBIT) {
                    //傳入進來的stamp不處於寫鎖狀態
                    if (a != m)
                        break;
                    //釋放寫鎖,上面在寫鎖的釋放有解釋,爲何不直接減去WBIT,再加上ORIGIN,釋放寫鎖加讀鎖
                    state = next = s + (WBIT + RUNIT);
                    //若是頭結點不爲空,而且頭結點的狀態不等於0 
                    if ((h = whead) != null && h.status != 0)
                        //釋放頭結點的下一個有效節點,在上面release方法時有介紹
                        release(h);
                    return next;
                }
                //若是傳進來的stamp是讀鎖狀態,直接返回傳進來的stamp
                else if (a != 0L && a < WBIT)
                    return stamp;
                //不然直接退出
                else
                    break;
            }
            return 0L;
    }複製代碼

  3. 升級爲樂觀讀

    //升級爲樂觀讀
    public long tryConvertToOptimisticRead(long stamp) {
            long a = stamp & ABITS, m, s, next; WNode h;
            //經過Unsafe的loadFence方法加入一個load內存屏障,目的是避免copy變量到工做內存中和升級樂觀讀的中鎖狀態校驗運算髮生重排序致使鎖狀態校驗不許確的問題,不清楚的話能夠看下我分享的UnSafe使用的內存屏障介紹 
            U.loadFence();
            for (;;) {
                //若是傳入進來的stamp和當前的StampedLock的狀態state不一致的話直接退出
                if (((s = state) & SBITS) != (stamp & SBITS))
                    break;
                //若是當前處於無鎖狀態,或者樂觀讀狀態
                if ((m = s & ABITS) == 0L) {
                    //若是傳入進來的stamp不是無鎖或者樂觀讀狀態直接退出
                    if (a != 0L)
                        break;
                    return s;
                }
                //若是當前處於寫鎖狀態
                else if (m == WBIT) {
                    //傳入進來的stamp不是寫鎖狀態,直接退出
                    if (a != m)
                        break;
                    //釋放寫鎖,上面有解釋爲何釋放寫鎖的時候不是直接減去1再加上ORIGIN
                    state = next = (s += WBIT) == 0L ? ORIGIN : s;
                    //若是頭結點不爲空,而且頭結點的狀態不爲0
                    if ((h = whead) != null && h.status != 0)
                         //看上面release方法的介紹
                         release(h);
                    return next;
                }
                //若是傳入的進來stamp&上255等於0,或者大於寫鎖狀態,直接退出
                else if (a == 0L || a >= WBIT)
                    break;
                //若是讀鎖沒有溢出,StampedLock的狀態state使用cas進行-1操做
                else if (m < RFULL) {
                    if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
                        //若是狀態cas操做完,變爲無鎖,而且頭結點不爲空,以及頭結點的狀態不爲0
                        if (m == RUNIT && (h = whead) != null && h.status != 0)
                            //看上面release方法的介紹
                            release(h);
                        return next & SBITS;
                    }
                }
                //若是讀鎖溢出,看上面對tryDecReaderOverflow方法的介紹
                else if ((next = tryDecReaderOverflow(s)) != 0L)
                    return next & SBITS;
            }
            return 0L;
    }複製代碼

9、其他方法

//獲取讀鎖的個數,傳入當前StampedLock的狀態state
private int getReadLockCount(long s) {
        long readers;
        //若是當前的讀鎖有溢出
        if ((readers = s & RBITS) >= RFULL)
            //返回的鎖個數爲RFULL加上溢出的鎖個數
            readers = RFULL + readerOverflow;
        //直接返回沒有溢出的讀鎖數 
        return (int) readers;
}

//判斷當前是否處於寫鎖狀態
public boolean isWriteLocked() {
        //當前狀態&上WBIT不爲0,代表當前處於寫鎖狀態
        return (state & WBIT) != 0L;
}    

//判斷當前是否處於讀鎖狀態
public boolean isReadLocked() {
        //當前狀態&上127不等於0,由於WBIT爲128,ORIGIN爲256,代表當前處於讀鎖狀態
        return (state & RBITS) != 0L;
}
    
//獲取當前讀鎖個數,調用上面getReadLockCount的私有方法
public int getReadLockCount() {
        return getReadLockCount(state);
}    

//重寫的toString方法 
public String toString() {
        long s = state;
        //根據當前狀態判斷StampedLock爲無鎖、或者讀鎖、寫鎖狀態
        return super.toString() +
            ((s & ABITS) == 0L ? "[Unlocked]" :
             (s & WBIT) != 0L ? "[Write-locked]" :
             "[Read-locks:" + getReadLockCount(s) + "]");
}    

//返回讀鎖視圖,返回上面介紹的內部類讀鎖視圖
public Lock asReadLock() {
        ReadLockView v;
        //不爲空直接返回,不然直接初始化
        return ((v = readLockView) != null ? v :
                (readLockView = new ReadLockView()));
}    

//返回寫鎖視圖,返回上面介紹的內部類寫鎖視圖
public Lock asWriteLock() {
        WriteLockView v;
        //不爲空直接返回,不然直接初始化
        return ((v = writeLockView) != null ? v :
                (writeLockView = new WriteLockView()));
}
    
//返回讀寫鎖視圖,返回上面介紹的內部類讀寫鎖視圖
public ReadWriteLock asReadWriteLock() {
        ReadWriteLockView v;
        //不爲空直接返回,不然直接初始化
        return ((v = readWriteLockView) != null ? v :
                (readWriteLockView = new ReadWriteLockView()));
}
    複製代碼

接下來也會持續對併發包中的其餘類進行分析,有不清楚的地方,或者分析的不對的地方也歡迎你們留言,一塊兒交流java

相關文章
相關標籤/搜索