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