关于java:java8新读写锁StampedLock学习

7次阅读

共计 2620 个字符,预计需要花费 7 分钟才能阅读完成。

StampedLock

最近看并发工具类的遇到这个玩意,据说效率比 ReentrantLock 高,咱也没用过,闲得慌,源码先扒了再说,不定期更新。

锁状态变量

既然是相似读写锁,必定也有变量用于记录锁状态,绝对于读写锁应用 Int,StampedLock 中使 Long 类型(64 位)示意锁状态,其中第 8 位示意写锁持有状态,低 7 位用于示意持有读锁的线程数。(目前还未搞懂为啥用 Long,待前面钻研)

    private static final long RUNIT = 1L; // 读锁线程减少时,// 获取写锁状态的掩码:1000 000
    private static final long WBIT  = 1L << LG_READERS; 
    // 获取读锁状态的掩码:0111 1111
    private static final long RBITS = WBIT - 1L;
    // 读锁持有数量的下限
    private static final long RFULL = RBITS - 1L;
    // 获取锁的状态,用于判断是否有线程持有读锁或写锁
    private static final long ABITS = RBITS | WBIT;
    //RBITS 取反,作用未钻研
    private static final long SBITS = ~RBITS; // note overlap with ABITS

写锁获取

    public long writeLock() {
        long s, next; 
        // 如果没有任何线程持有锁,CAS 尝试增加写锁状态
        // 如果失败,则 acquireWrite 办法中自旋尝试获锁,再次失败入队
        return ((((s = state) & ABITS) == 0L &&
                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
                next : acquireWrite(false, 0L));
    }

acquireWrite 办法巨长,真难看

 private long acquireWrite(boolean interruptible, long deadline) {
        WNode node = null, p;
        for (int spins = -1;;) { // spin while enqueuing
            long m, s, ns;
            // 再次尝试获取写锁,胜利则返回以后的锁状态
            if ((m = (s = state) & ABITS) == 0L) {if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
                    return ns;
            }
            else if (spins < 0)
                 // 写锁被其它线程占有,且期待队列为空(头等于尾)时,不批改 spins 
                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
            else if (spins > 0) {
                // 产生一个随机数,判断是否大于 0
                if (LockSupport.nextSecondarySeed() >= 0)
                    --spins;
            }
            else if ((p = wtail) == null) { // 初始化期待队列
                WNode hd = new WNode(WMODE, null);
                if (U.compareAndSwapObject(this, WHEAD, null, hd))
                    wtail = hd;
            }
            // 上面三个 if 就是将 node 采纳尾插法插入期待队列
            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);
                }
            }
        }
    }

正文完
 0