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);
}
}
}
}
发表回复