StampedLock source code analysis

I. Introduction

        StampedLock is JUC and contract inside JDK1.8 new version of a lock that provides read and write control three modes, when the call to get a lock function when the series will return to a long-type variable that is called to stamp (stamp), the stamp represents the state of the lock. We know that "read-write locks allow multiple threads simultaneously read shared variables for reading and writing little scenes." That reading and writing little scenes, the performance even better than StampedLock on read-write lock. ReadWriteLock supports two modes: one is a read lock, one is a write lock. The StampedLock supports three modes, namely: write lock, optimistic and pessimistic read lock read . Among them, write locks, semantic and ReadWriteLock pessimistic read locks to write locks, read lock semantics are very similar, allowing multiple threads simultaneously acquire pessimistic read lock, but allows only one thread acquires a write lock, write lock and pessimistic read lock is mutual - repellent. The difference is: after StampedLock in the pessimistic read lock and write lock lock successful, will return a stamp; then unlocked when the need to pass this stamp. try get the function lock series, when failure to acquire the lock will return to stamp value of 0. You need to pass to obtain stamp value when the lock is returned when you call to release the lock and the lock method when converting. The implementation is based on internal StampedLock CLH lock, CLH lock principle: Lock maintains a queue of waiting threads, application lock all the threads and failure are recorded in the queue. A node represents a thread, holds a flag locked, in order to determine whether the current thread releases the lock. When a thread attempts to acquire a lock, the end node from the queue as a prelude to the node, loop determines whether all the previous node has successfully releases the lock. Its core idea is that, when read in optimism if it does write, it should be to obtain a new value by retrying the way, should not be blocking write operations. This pattern is typical of lock-free programming ideas, and CAS spin thinking the same. This mode of operation determines the next StampedLock reading the thread very much and very few write-threaded scene is very suitable, but also to avoid starvation write happening. And reentrant StampedLock not supported and unsupported Condition, as shown (below the reference line in FIG. ):

Second, property

//处理器数量
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);    }}复制代码

Third, the constructor

//state被初始化为256,写锁标志位128,读锁位
public StampedLock() {    state = ORIGIN;}复制代码

Fourth, inner classes

//等待节点类
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()));   
    }
}复制代码

Fifth, write lock acquisition and release

  1. Write lock acquisition

    //获取排他锁,如果不能马上获取到,必要的时候会将其阻塞,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();
    }
    
    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;        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);            }        }    }}复制代码

Sixth, read lock acquisition and release

Seven optimistic reading obtaining, verification

Eight, lock escalation


Guess you like

Origin juejin.im/post/5d00a6c8e51d45105d63a4ed