JUC之StampedLock源码

前提

1.WNode源码分析

static final class WNode {

        volatile WNode prev;     //节点的前置连接
        volatile WNode next;     //节点的后置连接
        volatile WNode cowait;    //连续读节点的等待队列
        volatile Thread thread;   
        volatile int status;      // 0, WAITING, or CANCELLED
        final int mode;           // RMODE or WMODE (读节点或者写节点)
        WNode(int m, WNode p) { mode = m; prev = p; }
}

WNode中的pre与next代表的是等待队列的链表形态,队列包含写节点与读节点,而cowait代表的连续读节点的等待队列的链表形态;

WNode中的status有3中,0代表中间状态,-1代表后续有节点阻塞等待,1代表当前节点任务取消;

WNode中的mode有两种,RMODE=0代表读节点,WNode=1代表写节点;

WNode的构造函数,以节点类型和前置节点进行创建;

2.StampedLock中的state同步状态值采用分段的方式提供不同的功能,从右开始的7位代表的是读锁的同步状态,第8位代表写锁的同步状态,剩下的56位代表的是锁的版本号(邮戳);

3.state默认值为ORIGIN,也就是256,二进制1 0000 0000,这里代表版本号起始为1,且锁为空闲状态; 

一、WriteLockView(独占写锁)

 final class WriteLockView implements Lock {

        public void lock() { writeLock(); }
       
        public void unlock() { unstampedUnlockWrite(); }
        
}

public long writeLock() {
        long s, next;
        //这里的ABITS为255,二进制为1111 1111,state&ABITS代表的是去state的后8位
        //后8位的值是0代表写锁空闲
        return ((((s = state) & ABITS) == 0L &&
                //这里的WBIT为128,二进制为1000 0000,这里的操作其实是在state第8位加1
                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
                next : acquireWrite(false, 0L));
}

//interruptible代表中断发生后是否退出竞争(true退出竞争,false继续竞争)
//deadline代表等待的最大时间
private long acquireWrite(boolean interruptible, long deadline) {
        WNode node = null, p;
        for (int spins = -1;;) { // 自旋入队操作 spins为自旋数 
            long m, s, ns;
            //如果当前写锁空闲,就自旋获取锁 
            if ((m = (s = state) & ABITS) == 0L) {
                if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
                    return ns;
            }//在写锁占用的情况情况下,由于spins默认为-1,这里会进入对spins初始化
            else if (spins < 0)
                //当写锁为占用状态(state后8位为1000 0000)并且等待队列为空的情况下为64
                //这里的SPINS还要判断硬件能力,多核为64次,否则为0
                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
            else if (spins > 0) {//自旋逐减的操作
                //通过随机数判断,可以让线程自旋数不一致
                if (LockSupport.nextSecondarySeed() >= 0)
                    --spins;
            }
            else if ((p = wtail) == null) { //当队列为空的情况下,插入哨兵节点
                WNode hd = new WNode(WMODE, null);//创建一个前置为null,写类型的节点
                if (U.compareAndSwapObject(this, WHEAD, null, hd))//将该节点放入队列中
                    wtail = hd;
            }
            注1️⃣
            else if (node == null)//初始化我们要放入等待队列的当前线程节点
                node = new WNode(WMODE, p);//类型为写节点,前置节点为队列尾节点
            else if (node.prev != p)//当node的前置节点发生变化时,重置node的前置节点
                node.prev = p;
            else if (U.compareAndSwapObject(this, WTAIL, p, node)) {//将尾结点置为node
                p.next = node;//原尾结点的后置节点指向node,退出自旋
                break;
            }
        }
        //在上面自旋完成入队操作后
        for (int spins = -1;;) {
            WNode h, np, pp; int ps;
            //h重新指向队列头节点,当队列等于p,并不是队列为空的意思
            //这里代表的是node前置节点成为了头节点
            if ((h = whead) == p) {注2️⃣
                if (spins < 0)//初始化自旋数为1024
                    spins = HEAD_SPINS;
                else if (spins < MAX_HEAD_SPINS)//当自旋数小于65535就自乘以2
                    spins <<= 1;
                for (int k = spins;;) { //开始自旋
                    long s, ns;
                    if (((s = state) & ABITS) == 0L) {//写锁状态为空闲
                        if (U.compareAndSwapLong(this, STATE, s,
                                                 ns = s + WBIT)) {//cas操作state成功
                            whead = node;//将头节点置为node,node的前置置为null,返回ns
                            node.prev = null;
                            return ns;
                        }
                    }
                    else if (LockSupport.nextSecondarySeed() >= 0 &&
                             --k <= 0)//写锁专用情况下,自旋逐减
                        break;
                }
            }
            else if (h != null) { //这里头节点不是空的且不是node的前置节点
                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) {
                    //node的前置节点p发生改变,重置p,将p的后置节点指向node
                    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) {
                        //状态前置节点的前置节点pp,将pp与node相连,去掉p节点
                        node.prev = pp;
                        pp.next = node;
                    }
                }
                else {//这里进入阻塞阶段
                    long time; 
                    if (deadline == 0L)//0代表没有时间限制,可以无限等待
                        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;
                    /*当前置节点为-1并且前置节点不是头结点且写锁为占用状态,头节点与node的前            
                      置节点没有发生变化的情况下,阻塞当前线程*/
                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
                        whead == h && node.prev == p)
                        U.park(false, time);  // emulate LockSupport.park
                    node.thread = null;//醒来后,将节点线程置为null
                    U.putObject(wt, PARKBLOCKER, null);//线程阻塞对象置为null
                    if (interruptible && Thread.interrupted())//如果当断后处理为取消竞争
                        //发生中断后,这里会将当前节点任务取消掉
                        注3️⃣
                        return cancelWaiter(node, node, true);
                }
            }
        }
}

final void unstampedUnlockWrite() {
        WNode h; long s;
        if (((s = state) & WBIT) == 0L)//如果写锁未占用,则抛出异常
            throw new IllegalMonitorStateException();
        state = (s += WBIT) == 0L ? ORIGIN : s;//这里加128是为了进位修改版本号
        if ((h = whead) != null && h.status != 0)
        //当头结点不是空且状态不为0,唤醒后续节点
            release(h);
}

注意:

1.在注1的地方的3个分支处理,就是第一个自旋入队的操作,这里使用自旋是因为这是一个双向链表,插入到队列尾,需要两步改变,一步是node的前置节点的链接改变,另一步是node的前置节点的后置节点的链接改;这里可以看到先是node前置节点的指向队列尾节点,再把队列尾结点指针指向node后,最后将原尾结点的后置节点指向node,这是由于存在竞争的条件下,多个node会争抢修改队列尾指针指向,尾指针修改采用cas操作,修改失败的node会在下次循环会重置自己的前置节点,避免节点消失的问题。

2.在注2的地方的if处理中,里面是个自旋操作,这里的意义代表当node的前置节点为头结点时,代表node的前置节点抢到了资源,可能很快就到你了,不需要阻塞,所以这里有个自旋获取锁的操作,还有一点要注意,里面的自旋数的递增的,每次都是上一次自旋数的2倍,达到自旋最大值65536后就不会增加了,这样做的目的是为了线程利用率,保证每个线程获取资源的时间平均些。

3.注3的地方的取消节点操作,这里进行详细说明

private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
        if (node != null && group != null) {
            Thread w;
            node.status = CANCELLED;//node节点状态置为取消
            //连续读节点组中取消节点剔除
            for (WNode p = group, q; (q = p.cowait) != null;) {
                if (q.status == CANCELLED) {
                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
                    p = group; // restart
                }
                else
                    p = q;
            }
            //连续读节点组等于node本身代表node是等待队列中的节点
            if (group == node) {
                for (WNode r = group.cowait; r != null; r = r.cowait) {
                    if ((w = r.thread) != null)
                        U.unpark(w);       //唤醒读节点
                }
                //将node的前后包括本身的取消节点剔除队列
                for (WNode pred = node.prev; pred != null; ) {
                    WNode succ, pp;
                    //剔除node后面的取消节点       
                    while ((succ = node.next) == null ||
                           succ.status == CANCELLED) {
                        WNode q = null;
                        //从尾节点往前找node后的第一个正常节点   
                        for (WNode t = wtail; t != null && t != node; t = t.prev)
                            if (t.status != CANCELLED)
                                q = t;
                        //将node与后面的正常节点相连,剔除取消节点     
                        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) //将前置节点与node后面的正常节点相连
                        U.compareAndSwapObject(pred, WNEXT, node, succ);
                    if (succ != null && (w = succ.thread) != null) {
                        succ.thread = null;
                        U.unpark(w);//唤醒node后的正常节点,让他去修改自己的前置节点
                    }
                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
                        break;
                    node.prev = pp;//如果前置节点为取消节点,这里会剔除前置节点,并向前继续
                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
                    pred = pp;
                }
            }
        }
        WNode h; 
        while ((h = whead) != null) {//这里剔除头节点后的取消节点
            long s; WNode q;
            if ((q = h.next) == null || q.status == CANCELLED) {
                for (WNode t = wtail; t != null && t != h; t = t.prev)
                    if (t.status <= 0)
                        q = t;
            }
            if (h == whead) {//头节点无变化
                //头结点的后继节点符号条件,就唤醒
                //条件:后继节点不为空且状态中立且写锁空闲且(后继节点为读节点或者锁空闲)
                if (q != null && h.status == 0 &&
                    ((s = state) & ABITS) != WBIT && 
                    (s == 0L || q.mode == RMODE))
                    release(h);
                break;
            }
        }
        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
}

这里取消节点的操作主要是从队列中剔除,一个是从连续读节点队列中剔除,一个是从等待队列中剔除,但不只是剔除本身,还有队列中的其他取消节点。

二、ReadLockView(共享读锁)

 final class ReadLockView implements Lock {

        public void lock() { readLock(); }
      
        public void unlock() { unstampedUnlockRead(); }
      
}

public long readLock() {
        long s = state, next;
        //队列为空,且state取后8位,小于126时才可以直接获取读锁,不成功进入acuqireRead方法
        return ((whead == wtail && (s & ABITS) < RFULL && //RFULL=126
                 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
                next : acquireRead(false, 0L));
}

//interruptible代表中断发生后是否退出竞争(true退出竞争,false继续竞争)
//deadline代表等待的最大时间
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;;) {
                    //当state的后8位小于126,获取锁
                    //大于等于126小于128的话,可以获取读锁,溢出值变为1,state后8位为127
                    //大于等于128,代表有写锁处于占用状态,会周期性的让出线程的执行权
                    if ((m = (s = state) & ABITS) < RFULL ?
                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
                        return ns;
                    else if (m >= WBIT) {//有写锁处于占用状态
                        if (spins > 0) {//自旋逐减
                            if (LockSupport.nextSecondarySeed() >= 0)
                                --spins;
                        }
                        else {
                            if (spins == 0) {//自旋完成后
                                WNode nh = whead, np = wtail;
                                //头尾节点未发生变化,或者队列不为空,退出自旋
                                if ((nh == h && np == p) || (h = nh) != (p = np))
                                    break;
                            }
                            spins = SPINS;//初始化spins
                        }
                    }
                }
            }
            if (p == null) { //设置前置为null,类型为写类型的哨兵节点进入等待队列
                WNode hd = new WNode(WMODE, null);
                if (U.compareAndSwapObject(this, WHEAD, null, hd))
                    wtail = hd;
            }
            else if (node == null)//初始化当前线程的节点
                node = new WNode(RMODE, p);//读类型,前置节点为队列尾结点
            //队列为空(这里包括有哨兵节点的队列)或者尾结点的类型为写节点
            else if (h == p || p.mode != RMODE) {
                if (node.prev != p)//当队列尾结点发生变化,将node的前置节点重置
                    node.prev = p;
                //node前置节点无变化,这里修改尾节点指针指向node,原尾结点的后置节点为node
                else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
                    p.next = node;
                    break;//入队成功,退出循环了
                }
            }
            //这里也是一个入队操作,不过是针对连续读节点的
            //当尾结点也是读节点时,将node置入尾结点的cowait队列中
            //这里node会成为尾结点的直接cowait节点,以前的cowait节点成为node的cowait节点
            else if (!U.compareAndSwapObject(p, WCOWAIT,
                                             node.cowait = p.cowait, node))
                node.cowait = null;
            else {//这里是连续节点入队完成后,会自旋阻塞,这个阻塞不会修改前置节点的状态
                for (;;) {//自旋
                    WNode pp, c; Thread w;
                    if ((h = whead) != null && (c = h.cowait) != null &&
                        U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
                        (w = c.thread) != null) //唤醒头结点上的连续读节点 
                        U.unpark(w);
                    //由于连续读节点时挂在一个读节点上的,所以这里多判断了node前置节点的前置        
                    //节点为头结点的情况
                    if (h == (pp = p.prev) || h == p || pp == null) {
                        long m, s, ns;
                        do {//读锁未达到获取上线,自旋获取
                            if ((m = (s = state) & ABITS) < RFULL ?
                                U.compareAndSwapLong(this, STATE, s,
                                                     ns = s + RUNIT) :
                                (m < WBIT &&
                                 (ns = tryIncReaderOverflow(s)) != 0L))
                                return ns;
                        } while (m < WBIT);
                    }//头结点无变化且前置节点的前置节点无变化
                    if (whead == h && p.prev == pp) {
                        long time;
                        //pp为null或者p为取消节或者p为头节点,将不阻塞线程,退出自旋
                        if (pp == null || h == p || p.status > 0) {
                            node = null; // throw away
                            break;
                        }
                        if (deadline == 0L)
                            time = 0L;
                        else if ((time = deadline - System.nanoTime()) <= 0L)
                            return cancelWaiter(node, p, false);
                        Thread wt = Thread.currentThread();
                        U.putObject(wt, PARKBLOCKER, this);
                        node.thread = wt;
                        //头结点不是pp或者写锁占用状态并且头节点与pp无变化,阻塞当前线程
                        if ((h != pp || (state & ABITS) == WBIT) &&
                            whead == h && p.prev == pp)
                            U.park(false, time);
                        node.thread = null;
                        U.putObject(wt, PARKBLOCKER, null);
                        if (interruptible && Thread.interrupted())
                            return cancelWaiter(node, p, true);
                    }
                }
            }
        }

        for (int spins = -1;;) {
            WNode h, np, pp; int ps;
            if ((h = whead) == p) {//当node前置节点为头节点时
                if (spins < 0)//初始化spins
                    spins = HEAD_SPINS;
                else if (spins < MAX_HEAD_SPINS)
                    spins <<= 1;
                for (int k = spins;;) { // spin at head
                    long m, s, ns;
                    if ((m = (s = state) & ABITS) < RFULL ?
                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
                        WNode c; Thread w;
                        whead = node;
                        node.prev = null;
                        while ((c = node.cowait) != null) {
                            if (U.compareAndSwapObject(node, WCOWAIT,
                                                       c, c.cowait) &&
                                (w = c.thread) != null)
                                U.unpark(w);
                        }
                        return ns;
                    }
                    else if (m >= WBIT &&
                             LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
                        break;
                }
            }
            else if (h != null) {//唤醒头结点上连续的读节点
                WNode c; Thread w;
                while ((c = h.cowait) != null) {
                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
                        (w = c.thread) != null)
                        U.unpark(w);
                }
            }
            if (whead == h) {//头结点无变化
                if ((np = node.prev) != p) {//node前置发生变化重置
                    if (np != null)
                        (p = np).next = node;  
                }
                else if ((ps = p.status) == 0)//将前置的状态设为-1
                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
                else if (ps == CANCELLED) {//剔除取消节点
                    if ((pp = p.prev) != null) {
                        node.prev = pp;
                        pp.next = node;
                    }
                }
                else {//进入阻塞线程流程
                    long time;
                    if (deadline == 0L)
                        time = 0L;
                    else if ((time = deadline - System.nanoTime()) <= 0L)
                        return cancelWaiter(node, node, false);
                    Thread wt = Thread.currentThread();
                    U.putObject(wt, PARKBLOCKER, this);
                    node.thread = wt;
                    if (p.status < 0 &&
                        (p != h || (state & ABITS) == WBIT) &&
                        whead == h && node.prev == p)
                        U.park(false, time);
                    node.thread = null;
                    U.putObject(wt, PARKBLOCKER, null);
                    if (interruptible && Thread.interrupted())
                        return cancelWaiter(node, node, true);
                }
            }
        }
}

final void unstampedUnlockRead() {
        for (;;) {
            long s, m; WNode h;
            //这里是读锁未获取或者写锁占用的情况,抛出异常
            if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
                throw new IllegalMonitorStateException();
            else if (m < RFULL) {//读锁数量小于126,state-1
                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                    //只有队列中有一个节点时,才会进行唤醒
                    if (m == RUNIT && (h = whead) != null && h.status != 0)
                        release(h);
                    break;
                }
            }//溢出的情况,释放锁要将溢出值置为0
            else if (tryDecReaderOverflow(s) != 0L)
                break;
        }
}

三、ReadWriteLockView(读写锁)

final class ReadWriteLockView implements ReadWriteLock {
        public Lock readLock() { return asReadLock(); }
        public Lock writeLock() { return asWriteLock(); }
}

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()));
}

这个模式是上面两个模式的集合体,没有什么特殊的地方。

四、辅助方法

tryOptimisticRead()&validate()

public long tryOptimisticRead() {
        long s;
        //获取第8位的值,写锁状态空闲,返回一个版本号,否则为0
        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
}

public boolean validate(long stamp) {
        U.loadFence();
    //这里SBITS二进制为57个1加上7个0,这里&操作获取的是版本号,当版本号没有发生变化时,返回true
        return (stamp & SBITS) == (state & SBITS);
}

乐观读tryOptimisticRead是不上锁的,当我们使用乐观读时会返回一个版本号,这个版本号在我们做读操作之前进行验证,验证使用validate方法,true代表没有竞争,我们读取即可,否则代表已经出现竞争,读取就需要加共享读锁(ReadLock)了。

unlockRead(stamp)&unlock(stamp)&unlockWrite(stamp)

public void unlockRead(long stamp) {
        long s, m; WNode h;
        for (;;) {
            //这里比unstampedUnlockRead多了对stamp的判断
            //主要是版本号一致判断以及stamp锁状态判断
            if (((s = state) & SBITS) != (stamp & SBITS) ||
                (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
                throw new IllegalMonitorStateException();
            if (m < RFULL) {
                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                    if (m == RUNIT && (h = whead) != null && h.status != 0)
                        release(h);
                    break;
                }
            }
            else if (tryDecReaderOverflow(s) != 0L)
                break;
        }
}

 public void unlockWrite(long stamp) {
        WNode h;
        //也是多了stamp判断,这里直接判断stamp==state,因为写锁的独占模式的
        if (state != stamp || (stamp & WBIT) == 0L)
            throw new IllegalMonitorStateException();
        state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
        if ((h = whead) != null && h.status != 0)
            release(h);
}

public void unlock(long stamp) {
        long a = stamp & ABITS, m, s; WNode h;
        //判断版本号是否一致
        while (((s = state) & SBITS) == (stamp & SBITS)) {
            //没有持有锁就退出循环,直接抛异常
            if ((m = s & ABITS) == 0L)//m是state的后8位
                break;
            else if (m == WBIT) {//写锁释放
                if (a != m)
                    break;
                state = (s += WBIT) == 0L ? ORIGIN : s;
                if ((h = whead) != null && h.status != 0)
                    release(h);
                return;
            }
            //这里a是stamp的后8位 注1️⃣
            else if (a == 0L || a >= WBIT)
                break;
            else if (m < RFULL) {//读锁释放
                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
                    if (m == RUNIT && (h = whead) != null && h.status != 0)
                        release(h);
                    return;
                }
            }//溢出值处理
            else if (tryDecReaderOverflow(s) != 0L)
                return;
        }
        throw new IllegalMonitorStateException();
}

注1的地方我们发现这里的a>=WBIT,是写锁判断的意思,但是上面已经判断过了,这里为什么还有判断呢,其实上面的判断是state的写锁判断,而注1的地方判断的是你邮戳的写锁判断,这是有可能出现,比如你调用了两次unlock就会进入这个判断。

tryConvertToReadLock(stamp)

public long tryConvertToReadLock(long stamp) {
        long a = stamp & ABITS, m, s, next; WNode h;
        while (((s = state) & SBITS) == (stamp & SBITS)) {//锁的版本号没有发生改变
            if ((m = s & ABITS) == 0L) {//锁是空闲状态
                if (a != 0L)//锁过期的情况
                    break;
                else if (m < RFULL) {//读锁未达到上线,转化为读锁
                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
                        return next;
                }
                else if ((next = tryIncReaderOverflow(s)) != 0L)//溢出转换
                    return next;
            }
            else if (m == WBIT) {//写锁转换
                if (a != m)//锁过期的情况
                    break;
                state = next = s + (WBIT + RUNIT);//这里将写锁位置为0空闲,读锁位+1
                if ((h = whead) != null && h.status != 0)//唤醒后续节点
                    release(h);
                return next;
            }
            else if (a != 0L && a < WBIT)//本身就是读锁
                return stamp;
            else
                break;
        }
        return 0L;
}

写锁转化为读锁,本质是对state的修改,这里写锁的释放会唤醒后续等待节点,转化失败不会阻塞。

tryConvertToWriteLock(stamp)

public long tryConvertToWriteLock(long stamp) {
        long a = stamp & ABITS, m, s, next;
        while (((s = state) & SBITS) == (stamp & SBITS)) {
            if ((m = s & ABITS) == 0L) {//锁空闲状态
                if (a != 0L)//锁过期
                    break;
                if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))//写锁占用
                    return next;
            }
            else if (m == WBIT) {//本身为写锁
                if (a != m)
                    break;
                return stamp;
            }
            else if (m == RUNIT && a != 0L) {//读锁转换
                if (U.compareAndSwapLong(this, STATE, s,//读锁位-1,写锁位+1
                                         next = s - RUNIT + WBIT))
                    return next;
            }
            else
                break;
        }
        return 0L;
}

读锁转化为写锁,其实本质是对state的修改,将读锁释放,获取写锁,这里没有等待唤醒机制,转化失败就失败了,不会阻塞的。

tryConvertOptimisticRead(stamp)

public long tryConvertToOptimisticRead(long stamp) {
        long a = stamp & ABITS, m, s, next; WNode h;
        U.loadFence();
        for (;;) {
            if (((s = state) & SBITS) != (stamp & SBITS))//版本号发生变化,退出循环
                break;
            if ((m = s & ABITS) == 0L) {//无锁情况
                if (a != 0L)
                    break;
                return s;
            }
            else if (m == WBIT) {//写锁占用状况,释放写锁,转化为乐观读
                if (a != m)
                    break;
                state = next = (s += WBIT) == 0L ? ORIGIN : s;
                if ((h = whead) != null && h.status != 0)
                    release(h);
                return next;
            }
            else if (a == 0L || a >= WBIT)//锁过期
                break;
            else if (m < RFULL) {//释放共享读锁,转化为乐观读
                if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
                    if (m == RUNIT && (h = whead) != null && h.status != 0)
                        release(h);
                    return next & SBITS;
                }
            }//减掉溢出值释放读锁后,转化为乐观读
            else if ((next = tryDecReaderOverflow(s)) != 0L)
                return next & SBITS;
        }
        return 0L;
}

读写转化为乐观读,其实都是需要先释放本身的锁后,才能使用乐观读,乐观读本质上是无锁状态读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值