Java8 StampedLock(二) 源码解析

 目录

一、WriteLockView

1、lock / lockInterruptibly

2、tryLock

3、unlock 

 4、unlockWrite / tryUnlockWrite

二、ReadLockView

1、lock / lockInterruptibly

2、tryLock

3、unlock

4、unlockRead / tryUnlockRead

三、乐观读锁

四、锁转换

1、tryConvertToWriteLock / tryConvertToReadLock /tryConvertToOptimisticRead

2、unlock


    上一篇《Java8 StampedLock(一) 源码解析》详细讲解了该类的定义,具体的用法以及同ReentrantReadWriteLock的差异,本篇博客就详细分析源码实现细节。

一、WriteLockView

1、lock / lockInterruptibly

      相比ReentrantReadWriteLock的实现,StampedLock增加了基于for循环的自旋等待,在加入到同步链表前会自旋等待最多64次,加入到链表后,如果当前节点的前一个节点就是head节点,也会自旋等待,自旋的次数从1024次开始,每次for循环都会判断前一个节点是否还是head节点,如果是则将其扩容一倍,直到达到最大值65536次,每次自旋等待都会尝试获取锁。增加自旋等待的目的是为了减少线程休眠,线程上下文切换带来的性能损耗,提高抢占锁的效率。注意上述的最大自旋次数并不是实际的CPU自旋次数,因为只有当生成的随机数大于0时才认为是一次有效自旋,否则继续下一次的for循环。

    另外StampedLock的写锁不支持重入,当一个阻塞状态的节点被唤醒后会将thread属性置为null,即当前head节点的thread属性为null,无法将该属性与当前线程比较,无法判断是否当前线程持有的写锁。

public void lock() { writeLock(); }

public void lockInterruptibly() throws InterruptedException {
            writeLockInterruptibly();
        }

public long writeLock() {
        long s, next;  // bypass acquireWrite in fully unlocked case only
        return ((((s = state) & ABITS) == 0L && //等于0表示锁未被占用
                 //compareAndSwapLong返回true,表示原子修改成功,抢占锁成功
                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
                 //上述两个条件不成立表示需要进入等待队列了 
                next : acquireWrite(false, 0L));
    }

public long writeLockInterruptibly() throws InterruptedException {
        long next;
        if (!Thread.interrupted() &&
            (next = acquireWrite(true, 0L)) != INTERRUPTED)
            return next;
         //如果线程中断了则抛出异常   
        throw new InterruptedException();
    }

//interruptible表示是否检查线程中断,deadline表示等待的最后时间,如果无期限则是0
private long acquireWrite(boolean interruptible, long deadline) {
        WNode node = null, p;
        //将加入链表的动作分解成多步,每一步都是一次for循环,每次都会尝试抢占锁,从而提高抢占锁的效率
        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)
                //m是且运算后的结果,等于WBIT说明该写锁已经被占用了
                //wtail和whead相等,可能都是null,也可能是某个节点,总之此时只有一个线程占有锁,所以就自旋等待该线程释放锁
                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
            else if (spins > 0) {
                //在上一个if分支初始化spins后再for循环,如果锁未释放则进入此分支
                //通过nextSecondarySeed获取一个随机数,如果大于0,则将spins减一,否则继续下一次for循环
                //会不断for循环直到spins变成0
                if (LockSupport.nextSecondarySeed() >= 0)
                    --spins;
            }
            else if ((p = wtail) == null) { //spins等于0是会进入此分支
                //创建一个空节点,原子的修改whead和wtail指向该节点
                WNode hd = new WNode(WMODE, null);
                if (U.compareAndSwapObject(this, WHEAD, null, hd))
                    wtail = hd;
            }
            else if (node == null)
                //whead和wtail都初始化后进入此分支
                node = new WNode(WMODE, p);
            else if (node.prev != p)
                //node赋值了,prev属性未赋值时进入此分支
                node.prev = p;
            else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
                //node的prev属性赋值了,将其原子的设置为wtail,插入到原来的tail的后面
                p.next = node;
                break;
            }
        } //for循环结束
       
        //上面的for循环在多次尝试获取锁后用当前线程创建一个WNode并插入到链表末尾
        for (int spins = -1;;) {
            WNode h, np, pp; int ps;
            //p就是原来的wtail节点,whead等于p说明下一个被唤醒的节点就是node,通过自旋等待现在的whead节点对应的线程释放锁
            if ((h = whead) == p) {
                if (spins < 0)
                    //初始化spins
                    spins = HEAD_SPINS;
                else if (spins < MAX_HEAD_SPINS)
                    //将spins左移一位,即扩大一倍
                    spins <<= 1;
                //spins通过外层for循环达到最大值后,还是会自旋,只是自旋的次数不在增长了        
                for (int k = spins;;) { //通过for循环自旋spin次,每次都尝试获取锁
                    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 && 
                             //如果返回的随机值大于0,将k减1,直到k小于0,for循环退出
                             --k <= 0)
                        break;
                }//for循环结束
            }else if (h != null) { //还有其他的等待节点
                WNode c; Thread w;
                //遍历whead的cowait链表中的节点,将其对应的线程唤醒
                //cowait链表中的元素是获取读锁时插入的,里面的节点都是获取读锁的线程
                //此处将他们唤醒,他们也会自旋等待head节点释放锁
                while ((c = h.cowait) != null) {
                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && //将whead的cowait属性设置为该链表的下一个元素
                        (w = c.thread) != null)
                        U.unpark(w);
                }
            }
            
            //如果whead不等于p,有其他的等待节点
            if (whead == h) {
                //链表头没有改变,即未释放锁,如果变了就通过下一轮for循环抢占锁
                if ((np = node.prev) != p) {
                    //node前面的节点变了
                    if (np != null)
                        (p = np).next = node;   // stale
                }
                else if ((ps = p.status) == 0)
                    //将状态原子的修改为WAITING
                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
                else if (ps == CANCELLED) {
                    //node的前一个节点的状态是CANCELLED,将其移除,通过外层的for循环将连续的多个CANCELLED节点删除
                    if ((pp = p.prev) != null) {
                        node.prev = pp;
                        pp.next = node;
                    }
                }else {
                    //前面一个节点的状态是WAITING,肯定不是CANCELLED和0
                    long time; // 0 argument to park means no timeout
                    if (deadline == 0L)
                        time = 0L;
                    else if ((time = deadline - System.nanoTime()) <= 0L)
                        //如果剩余时间不足,将其标记成CANCELLED
                        return cancelWaiter(node, node, false);

                    Thread wt = Thread.currentThread();
                    U.putObject(wt, PARKBLOCKER, this);
                    node.thread = wt;
                    if (p.status < 0 //p的状态是WAITING
                        && (p != h || (state & ABITS) != 0L) //当前锁被其他线程占用了
                        && whead == h  //whead节点没有变动
                        && node.prev == p)  //node的上一个节点没有变动
                        U.park(false, time);  //将当前线程阻塞掉
                    //线程被唤醒或者上面的if条件不成立
                    node.thread = null;
                    U.putObject(wt, PARKBLOCKER, null);
                    if (interruptible && Thread.interrupted())//如果线程被中断了
                        return cancelWaiter(node, node, true);
                }
            }
        } //for循环结束
    }

private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
        if (node != null && group != null) {
            Thread w;
            //将状态置为CANCELLED
            node.status = CANCELLED;
            //遍历group的cowait链表,如果节点是CANCELLED,将其从链表中移除
            for (WNode p = group, q; (q = p.cowait) != null;) {
                if (q.status == CANCELLED) {
                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
                    p = group; //从group开始重新遍历
                }
                else
                   //遍历链表中下一个元素
                    p = q;
            }
            //acquireWrite调用时这两个是一样的
            if (group == node) {
                //唤醒group cowait链表中所有节点对应的线程
                //node被取消了,但是cowait链表中的节点还是有效的,将其唤醒后,他们会重新插入到同步链表中等待被唤醒
                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
                    //如果node的下一个节点为null或者状态是CANCELLED
                    //如果node的下一个节点不是CANCELLED就不会进入while循环
                    while ((succ = node.next) == null ||
                           succ.status == CANCELLED) {
                        WNode q = null;    // find successor the slow way
                        //从wtail往前遍历找到node后的第一个不是CANCELLED的节点
                        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 ||   //succ和q都是null
                            //succ和q不等,说明succ和q都不是null,将node的next属性修改成q
                            U.compareAndSwapObject(node, WNEXT,
                                                   succ, succ = q)) {
                            if (succ == null && node == wtail) //如果node就是最后一个节点,将前一个节点作为WTAIL,退出while循环
                                U.compareAndSwapObject(this, WTAIL, node, pred);
                            break;
                        }
                    }
                    //上面while循环退出,succ要么为null,此时pred作为wtail,要么为一个非CANCELLED节点
                    //将pred的next属性修改为succ
                    if (pred.next == node) // unsplice pred link
                        U.compareAndSwapObject(pred, WNEXT, node, succ);
                    if (succ != null && (w = succ.thread) != null) {
                        //唤醒succ对应的线程
                        succ.thread = null;
                        U.unpark(w);       // wake up succ to observe new pred
                    }
                    //如果前一个节点的状态不是CANCELLED则终止循环
                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
                        break;
                    //前一个节点的状态是CANCELLED且pp非空
                    //将prev移除,pp的next指向succ    
                    node.prev = pp;        // repeat if new pred wrong/cancelled
                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
                    pred = pp;
                }
            }
        }//if结束
        //node或者group有一个为空
        WNode h; // Possibly release first waiter
        while ((h = whead) != null) {
            long s; WNode q; // similar to release() but check eligibility
            //如果下一个节点为null或者是CANCELLED
            if ((q = h.next) == null || q.status == CANCELLED) {
                //从wtail往前遍历,找到h后的第一个status小于0的节点
                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;
    }

    private void release(WNode h) {
        if (h != null) {
            WNode q; Thread w;
            //将h的状态由WAITING改成0
            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;
            }
            //唤醒q对应的线程
            if (q != null && (w = q.thread) != null)
                U.unpark(w);
        }
    }

2、tryLock

public boolean tryLock() { return tryWriteLock() != 0L; }

public boolean tryLock(long time, TimeUnit unit)
            throws InterruptedException {
            return tryWriteLock(time, unit) != 0L;
        }

public long tryWriteLock() {
        long s, next;
        //跟writeLock的实现一致,区别在于,如果条件不成立,tryWriteLock返回0,writeLock调用acquireWrite方法
        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;
            if ((next = tryWriteLock()) != 0L) //尝试获取锁成功
                return next;
            if (nanos <= 0L)
                return 0L;
            if ((deadline = System.nanoTime() + nanos) == 0L) //deadline超过允许的最大值了
                deadline = 1L;//置为1
            //通过acquireWrite获取锁,如果不是被中断的    
            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
                return next;
        }
        //如果被中断则抛出异常
        throw new InterruptedException();
    }

3、unlock 

        因为StampedLock的写锁不支持重入,所以此处unlock没有检查state等于0,也没有将state减去WBIT,相反还加了一个WBIT,如果达到最大值了则将其恢复成初始值ORIGIN,即写锁是否被占用了不是通过state的值来判断的,而是通过WBIT对应的第8位的位,如果是1表示占有了写锁,如果是0则表示写锁被释放了。

public void unlock() { unstampedUnlockWrite(); }

final void unstampedUnlockWrite() {
        WNode h; long s;
        //如果未获取写锁则抛出异常
        if (((s = state) & WBIT) == 0L)
            throw new IllegalMonitorStateException();
        //如果s达到最大值将恢复成初始值    
        state = (s += WBIT) == 0L ? ORIGIN : s;
        //加入到链表后状态会变成WAITING   
        if ((h = whead) != null && h.status != 0)
            //唤醒下一个节点  
            release(h);
    }

private void release(WNode h) {
        if (h != null) {
            WNode q; Thread w;
            //将状态从WAITING置为0
            U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
            if ((q = h.next) == null || q.status == CANCELLED) {
                //next为空或者状态是CANCELLED,从wtail往前遍历找到h后第一个状态为WAITING的节点
                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);
        }
    }

 4、unlockWrite / tryUnlockWrite

       unlockWrite是与writeLock、writeLockInterruptibly或者tryWriteLock 配合使用的,这三个方法返回成功加锁时的state属性值,unlockWrite据此解锁。tryUnlockWrite的实现和unstampedUnlockWrite类似,区别在于如果当前线程不持有写锁,前者返回false,后者抛出异常,如下:

public void unlockWrite(long stamp) {
        WNode h;
        //state变了或者求其等于0都说明当前线程未占有锁,则抛出异常
        //占有锁时,因为写锁只能一个线程占有,所以state值是不变的
        if (state != stamp || (stamp & WBIT) == 0L)
            throw new IllegalMonitorStateException();
        //如果stamp达到最大值了,则重置成ORIGIN初始值
        state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
        if ((h = whead) != null && h.status != 0)
            //唤醒下一个节点
            release(h);
    }

public boolean tryUnlockWrite() {
        long s; WNode h;
        if (((s = state) & WBIT) != 0L) {
            //如果没有占有锁,返回false
            //如果stamp达到最大值了,则重置成ORIGIN初始值
            state = (s += WBIT) == 0L ? ORIGIN : s;
            if ((h = whead) != null && h.status != 0)
                //唤醒下一个节点
                release(h);
            return true;
        }
        return false;
    }

二、ReadLockView

1、lock / lockInterruptibly

        获取读锁的过程中也加入了自旋等待的逻辑,如果当前只有一个节点,自旋等待该节点释放锁,自旋最多64次,同样的只有返回的随机数大于0才认为是一次有效自旋,否则继续内层的for循环,即实际的自旋等待次数最大不止64次。如果有多个节点或者自旋等待达到最大次数了whead节点未释放锁则往同步链表中添加一个新节点,同样的添加新节点逻辑被拆分成多个,每执行一部分逻辑就走外层for循环一遍,尝试抢占锁。注意如果wtail节点是写锁节点则在后面插入一个新的节点,如果是读锁节点,则在该节点的cowait链表中插入新节点。加入到cowait后线程会阻塞,再次唤醒时会检查之前的写锁是否被释放了,如果是则获取读锁。加入到同步链表后,会将状态改成WAITIN,然后被阻塞,再次唤醒时会检查是否被中断,检查当前是否只有一个节点了,如果只有一个则自旋等待最多1024次,同样的返回的随机数大于0才认为是一次有效自旋,否则继续内层的for循环,达到1024后还是一个节点,则将自旋等待的次数扩大一倍后继续自旋,直到达到最大值65536不再扩容,但是依然会自旋等待。

public void lock() { readLock(); }

public void lockInterruptibly() throws InterruptedException {
            readLockInterruptibly();
        }

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
                next : acquireRead(false, 0L));//获取读锁失败则调用acquireRead
}

public long readLockInterruptibly() throws InterruptedException {
        long next;
        if (!Thread.interrupted() && //线程没有被中断
            (next = acquireRead(true, 0L)) != INTERRUPTED)
            return next;
        throw new InterruptedException();
    }

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 ? //读锁重入的次数小于最大值且此时写锁未被占有
                        //上述条件成立,则修改state,修改成功表示获取读锁成功
                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
                        //上述条件不成立,如果w小于WBIT说明写锁没有被占用,此时还是读锁,但是读锁的重入次数达到最大值了
                        //tryIncReaderOverflow不等于0说明增加readerOverflow成功,则表示获取读锁成功,返回ns
                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
                        return ns;
                    else if (m >= WBIT) {
                        //说明此时写锁被占有了
                        if (spins > 0) {
                            //如果生成的随机数大于0,将spins减1
                            if (LockSupport.nextSecondarySeed() >= 0)
                                --spins;
                        }
                        else {
                            if (spins == 0) {
                                //达到最大自旋次数,注意自旋是内层的for循环,自旋过程中h和p都是不改变的
                                WNode nh = whead, np = wtail;
                                if ((nh == h && np == p) //链表头和链表尾没有改变,即写锁未释放
                                    || (h = nh) != (p = np) //链表头和链表尾不一样了,即有新的等待节点
                                    )
                                    break;//终止for循环
                            }
                            //初始化spins
                            spins = SPINS;
                        }
                    }
                }//for循环结束
            }//if结束
            //长时间写锁未释放或者有新的等待节点
            //p就是wtail
            if (p == null) { //初始化链表
                WNode hd = new WNode(WMODE, null);
                if (U.compareAndSwapObject(this, WHEAD, null, hd))
                    wtail = hd;
            }
            else if (node == null) //初始化node属性
                node = new WNode(RMODE, p);
            else if (h == p || p.mode != RMODE) {
                //h等于p说明没有其他等待节点了
                //p.mode != RMODE说明wtail节点是获取写锁的节点
                if (node.prev != p)
                    node.prev = p;//设置prev属性
                else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
                    //修改wtail为node,然后终止外层for循环,进入第二个大的for循环
                    p.next = node;
                    break;
                }
            }
            //有其他的等待节点且wtail节点是获取读锁的节点
            //将node的cowait赋值成p的cowait,将p的cowait属性修改为node,即把node加入到p的cowait链表中
            //此时不在插入一个新节点
            else if (!U.compareAndSwapObject(p, WCOWAIT,
                                             node.cowait = p.cowait, node))
                //如果修改失败,说明有线程在并发的获取读锁,将cowait置为null,通过外层for循环再次重试                             
                node.cowait = null;
            else {
                //上述compareAndSwapObject修改成功,即node成功加入到p的cowait链表中,开始新的for循环,此时p是一个获取读锁的节点,p的前一个节点肯定是获取写锁的节点
                for (;;) {
                    WNode pp, c; Thread w;
                    //借助for循环,将head节点上的cowait链表节点对应的线程都唤醒,唤醒后会自旋等待head节点释放锁
                    //如果head节点本身就是获取读锁的节点,则直接获取读锁
                    if ((h = whead) != null && (c = h.cowait) != null &&  //whead的cowait不为空
                        U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && //将whead的cowait修改为c的cowait
                        (w = c.thread) != null) // help release
                        U.unpark(w); //唤醒whead的cowait对应的线程

                    if (h == (pp = p.prev) || h == p || pp == null) {
                        //h等于p说明之前的写锁节点已经释放了,当前head节点就是获取读锁的节点,通过下面的while循环获取读锁
                        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)) //达到最大次数了,增加readerOverflow属性
                                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; //终止内层for循环
                        }
                        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) //链表头和p的前一个节点未改变
                            U.park(false, time); //将当前线程阻塞,当p节点变成链表头后会唤醒当前节点,然后走上一个if分支获取锁
                        //线程被唤醒    
                        node.thread = null;
                        U.putObject(wt, PARKBLOCKER, null);
                        if (interruptible && Thread.interrupted()) //如果是被中断的
                            return cancelWaiter(node, p, true);
                    }
                }//内层for循环结束
            }
        } //最外层的for循环结束
        
        //当前面一个节点是写锁节点,然后插入了一个新的读锁节点后会跳出最外层循环,进入此逻辑
        //此时p为上一个节点
        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) ://重入锁的次数没有到最大值,增加state属性
                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { //达到最大次数了,增加readerOverflow属性
                        //获取读锁成功
                        WNode c; Thread w;
                        whead = node;
                        node.prev = null;
                        //唤醒cowait链表中所有节点
                        while ((c = node.cowait) != null) {
                             //原子的修改node的cowait属性指向下一个cowait节点
                            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;
                //还有其他的等待节点,唤醒head上cowait链表节点对应的线程,被唤醒后他们会自旋等待head节点的写锁释放
                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) {
                     //node的前一个节点变了
                    if (np != null)
                        (p = np).next = node;   // stale
                }
                else if ((ps = p.status) == 0)
                    //将p的状态修改成WAITING
                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
                else if (ps == CANCELLED) {
                     //将节点p移除
                    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的状态是WAITING
                        (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); //线程被中断,将该节点置为CANCELLED
                }
            }
        }//for循环结束
    }

private long tryIncReaderOverflow(long s) {
        // assert (s & ABITS) >= RFULL;
        if ((s & ABITS) == RFULL) {
            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
                //增加readerOverflow
                ++readerOverflow;
                //恢复state
                state = s;
                return s;
            }
        }
        else if ((LockSupport.nextSecondarySeed() &
                  OVERFLOW_YIELD_RATE) == 0)
            Thread.yield();
        return 0L;
    }

2、tryLock

public boolean tryLock() { return tryReadLock() != 0L; }

public boolean tryLock(long time, TimeUnit unit)
            throws InterruptedException {
            return tryReadLock(time, unit) != 0L;
        }

public long tryReadLock() {
        for (;;) {
            long s, m, next;
            if ((m = (s = state) & ABITS) == WBIT)//如果写锁被占用了,返回0
                return 0L;
            else if (m < RFULL) {
                //如果写锁未被占用,读锁重入次数未达到最大值,则修改state属性成功
                if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
                    return next;
            }
            //读锁重入次数未达到最大值,增加readerOverflow成功
            else if ((next = tryIncReaderOverflow(s)) != 0L)
                return next;
        }
    }

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;
            }
            //尝试获取读锁失败或者写锁被占用了,通过acquireRead获取读锁
            if (nanos <= 0L)
                return 0L; 
            if ((deadline = System.nanoTime() + nanos) == 0L) //超过最大值了
                deadline = 1L;
            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
                return next;
        }
        throw new InterruptedException();
    }

3、unlock

      读锁支持锁重入,因此unlock需要检查锁重入的次数是否减到0了,如果state中保存的锁重入次数达到最大值了,则将readOverflow属性减1,否则将state中的锁重入次数减1,直到其变成0了,读锁释放,唤醒同步链表中的下一个节点。

public void unlock() { unstampedUnlockRead(); }

final void unstampedUnlockRead() {
        for (;;) {
            long s, m; WNode h;
            //如果没有获取读锁或者写锁被占用了,则抛出异常
            if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
                throw new IllegalMonitorStateException();
            else if (m < RFULL) {
                //如果没有达到最大次数,将state减1
                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                    if (m == RUNIT && (h = whead) != null && h.status != 0)
                        //如果锁重入次数变成0了,则唤醒下一个节点对应的线程
                        release(h);
                    break;
                }
            }
            else if (tryDecReaderOverflow(s) != 0L) //达到最大次数了,减少readerOverflow属性
                break;
        }
    }

    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;
                //将readerOverflow减1,state不变
                if ((r = readerOverflow) > 0) {
                    readerOverflow = r - 1;
                    next = s;
                }
                else
                    //如果readerOverflow等于0了,则修改state属性
                    next = s - RUNIT;
                 state = next;
                 return next;
            }
        }
        else if ((LockSupport.nextSecondarySeed() &
                  OVERFLOW_YIELD_RATE) == 0)
            Thread.yield();
        return 0L;
    }

4、unlockRead / tryUnlockRead

     unlockRead与直接使用readLock、readLockInterruptibly或tryReadLock时配合使用,这三个方法返回加锁成功时的state值,unllockRead据此解锁;tryUnlockRead也是解锁,区别在于如果当前线程没有占有读锁,前者抛出异常,后者返回false,如下:

public void unlockRead(long stamp) {
        long s, m; WNode h;
        for (;;) {
            //将state与SBITS求且,算出来的是加写锁的累计次数,如果两个不等说明加了写锁,因为读锁未释放时不能加写锁
            //所以如果state和stamp求且的结果不等,说明当前线程未获取写锁,抛出异常
            if (((s = state) & SBITS) != (stamp & SBITS) ||
                (stamp & ABITS) == 0L //stamp下读锁和写锁都没有占有,stamp为非法值
                || (m = s & ABITS) == 0L //state下读锁和写锁都没有占有 
                || 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)
                        //如果锁重入次数减到0了,表示读锁完全释放了,唤醒下一个节点
                        release(h);
                    break;
                }
            }
            else if (tryDecReaderOverflow(s) != 0L)
                //达到最大锁重入次数了,减少readerOverflow属性
                break;
        }
    }

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) //达到最大锁重入次数了,减少readerOverflow属性
                return true;
        }
        //没有占有读锁
        return false;
    }

三、乐观读锁

      乐观读锁的实现就是基于两个方法,tryOptimisticRead 和 validate,tryOptimisticRead会判断写锁是否被占用,如果是返回0,否则返回写锁被占用的累计次数;validate判断写锁被占用的累计次数是否改变,如果改变则说明写锁被占用了,不能获取读锁;否则没有被占用,可以获取读锁,其实现如下:

public long tryOptimisticRead() {
        long s;
        //如果没有加写锁,返回此时获取写锁的累计次数,否则返回0
        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
    }

public boolean validate(long stamp) {
        //内存屏障,让之前的写操作指令都回写到内存中
        U.loadFence();
        //判断写锁的累计次数是否发生改变,如果改变了,说明写锁被占用了,返回false,否则返回true
        return (stamp & SBITS) == (state & SBITS);
    }

四、锁转换

1、tryConvertToWriteLock / tryConvertToReadLock /tryConvertToOptimisticRead

      三种锁都有对应的tryConvertTo方法,其实现如下:

public long tryConvertToWriteLock(long stamp) {
        long a = stamp & ABITS, m, s, next;
         //如果写锁的次数未发生改变,从stamp到现在未获取过写锁或者写锁一直没释放
        while (((s = state) & SBITS) == (stamp & SBITS)) {
            //如果是乐观读锁
            if ((m = s & ABITS) == 0L) {
                //stamp不是乐观读锁
                if (a != 0L)
                    break; 
                if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
                    return next;
            }
            else if (m == WBIT) {//当前写锁被占用了
                if (a != m) //stamp没有占用写锁
                    break;
                //a等于m    
                return stamp;
            }
            else if (m == RUNIT && a != 0L) {//当前读锁被占用了,且只重入了一次,a不等于0,stamp也是读锁
                 //减去RUNIT表示释放读锁,加上WBIT表示获取写锁
                 if (U.compareAndSwapLong(this, STATE, s,
                                         next = s - RUNIT + WBIT))
                    return next;
            }
            else
                break;
        }
        return 0L;
    }

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;
                //a也是乐观读锁   
                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;
                //a也是写锁,加WBIT是释放写锁,加RUNIT是获取读锁    
                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;
    }

    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) { //如果当前是乐观读锁,stamp也是乐观读锁
                if (a != 0L)
                    break;
                return s;
            }
            else if (m == WBIT) { //当前是写锁
                if (a != m)
                    break;
                //stamp也是写锁,将写锁释放    
                state = next = (s += WBIT) == 0L ? ORIGIN : s;
                if ((h = whead) != null && h.status != 0)
                    //写锁释放,唤醒下一个节点
                    release(h);
                return next;
            }
            //当前是读锁
            else if (a == 0L || a >= WBIT) //stamp是乐观读锁或者写锁
                            break;
            //stamp也是读锁                
            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;
    }

2、unlock

     unlock是配合锁转换使用的,通用的解锁方法,其实现如下:

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;
                 //a等于m,a也是写锁
                //释放写锁
                state = (s += WBIT) == 0L ? ORIGIN : s;
                if ((h = whead) != null && h.status != 0)
                    //唤醒下一个节点
                    release(h);
                return;
            }
            //当前是读锁,stamp是乐观锁或者写锁
            else if (a == 0L || a >= WBIT)
                break;
            //当前是读锁,stamp是读锁
            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;
        }
        //退出while循环抛出异常
        throw new IllegalMonitorStateException();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值