--- jsr166/src/jsr166e/StampedLock.java 2013/01/28 17:23:04 1.34
+++ jsr166/src/jsr166e/StampedLock.java 2015/09/13 16:28:14 1.41
@@ -6,12 +6,10 @@
package jsr166e;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.LockSupport;
/**
* A capability-based lock with three modes for controlling read/write
@@ -30,12 +28,12 @@ import java.util.concurrent.locks.LockSu
* in method {@link #unlockWrite} to release the lock. Untimed and
* timed versions of {@code tryWriteLock} are also provided. When
* the lock is held in write mode, no read locks may be obtained,
- * and all optimistic read validations will fail.
+ * and all optimistic read validations will fail.
*
*
Reading. Method {@link #readLock} possibly blocks
* waiting for non-exclusive access, returning a stamp that can be
* used in method {@link #unlockRead} to release the lock. Untimed
- * and timed versions of {@code tryReadLock} are also provided.
+ * and timed versions of {@code tryReadLock} are also provided.
*
* Optimistic Reading. Method {@link #tryOptimisticRead}
* returns a non-zero stamp only if the lock is not currently held
@@ -53,7 +51,7 @@ import java.util.concurrent.locks.LockSu
* invoke method {@code validate()}. For example, such steps are
* typically required when first reading an object or array
* reference, and then accessing one of its fields, elements or
- * methods.
+ * methods.
*
*
*
@@ -119,34 +117,17 @@ import java.util.concurrent.locks.LockSu
* }
* }
*
- * double distanceFromOriginV1() { // A read-only method
- * long stamp;
- * if ((stamp = sl.tryOptimisticRead()) != 0L) { // optimistic
- * double currentX = x;
- * double currentY = y;
- * if (sl.validate(stamp))
- * return Math.sqrt(currentX * currentX + currentY * currentY);
- * }
- * stamp = sl.readLock(); // fall back to read lock
- * try {
- * double currentX = x;
- * double currentY = y;
- * return Math.sqrt(currentX * currentX + currentY * currentY);
- * } finally {
- * sl.unlockRead(stamp);
- * }
- * }
- *
- * double distanceFromOriginV2() { // combines code paths
- * double currentX = 0.0, currentY = 0.0;
- * for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) {
- * try {
- * currentX = x;
- * currentY = y;
- * } finally {
- * if (sl.tryConvertToOptimisticRead(stamp) != 0L) // unlock or validate
- * break;
- * }
+ * double distanceFromOrigin() { // A read-only method
+ * long stamp = sl.tryOptimisticRead();
+ * double currentX = x, currentY = y;
+ * if (!sl.validate(stamp)) {
+ * stamp = sl.readLock();
+ * try {
+ * currentX = x;
+ * currentY = y;
+ * } finally {
+ * sl.unlockRead(stamp);
+ * }
* }
* return Math.sqrt(currentX * currentX + currentY * currentY);
* }
@@ -215,7 +196,11 @@ public class StampedLock implements java
* incoming reader arrives while read lock is held but there is a
* queued writer, this incoming reader is queued. (This rule is
* responsible for some of the complexity of method acquireRead,
- * but without it, the lock becomes highly unfair.)
+ * but without it, the lock becomes highly unfair.) Method release
+ * does not (and sometimes cannot) itself wake up cowaiters. This
+ * is done by the primary thread, but helped by any other threads
+ * with nothing better to do in methods acquireRead and
+ * acquireWrite.
*
* These rules apply to threads actually queued. All tryLock forms
* opportunistically try to acquire locks regardless of preference
@@ -259,11 +244,14 @@ public class StampedLock implements java
/** Number of processors, for spin control */
private static final int NCPU = Runtime.getRuntime().availableProcessors();
- /** Maximum number of retries before blocking on acquisition */
+ /** Maximum number of retries before enqueuing on acquisition */
private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
+ /** Maximum number of retries before blocking at head on acquisition */
+ private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
+
/** Maximum number of retries before re-blocking */
- private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0;
+ private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
/** The period for yielding when waiting for overflow spinlock */
private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
@@ -358,6 +346,8 @@ public class StampedLock implements java
* Behavior under timeout and interruption matches that specified
* for method {@link Lock#tryLock(long,TimeUnit)}.
*
+ * @param time the maximum time to wait for the lock
+ * @param unit the time unit of the {@code time} argument
* @return a stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
* @throws InterruptedException if the current thread is interrupted
@@ -405,8 +395,8 @@ public class StampedLock implements java
* @return a stamp that can be used to unlock or convert mode
*/
public long readLock() {
- long s, next; // bypass acquireRead on fully unlocked case only
- return ((((s = state) & ABITS) == 0L &&
+ 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 : acquireRead(false, 0L));
}
@@ -437,6 +427,8 @@ public class StampedLock implements java
* Behavior under timeout and interruption matches that specified
* for method {@link Lock#tryLock(long,TimeUnit)}.
*
+ * @param time the maximum time to wait for the lock
+ * @param unit the time unit of the {@code time} argument
* @return a stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
* @throws InterruptedException if the current thread is interrupted
@@ -502,7 +494,8 @@ public class StampedLock implements java
* obtained from {@link #tryOptimisticRead} or a locking method
* for this lock has no defined effect or result.
*
- * @return true if the lock has not been exclusively acquired
+ * @param stamp a stamp
+ * @return {@code true} if the lock has not been exclusively acquired
* since issuance of the given stamp; else false
*/
public boolean validate(long stamp) {
@@ -680,7 +673,7 @@ public class StampedLock implements java
long a = stamp & ABITS, m, s, next; WNode h;
for (;;) {
s = U.getLongVolatile(this, STATE); // see above
- if ((s & SBITS) != (stamp & SBITS))
+ if (((s = state) & SBITS) != (stamp & SBITS))
break;
if ((m = s & ABITS) == 0L) {
if (a != 0L)
@@ -715,7 +708,7 @@ public class StampedLock implements java
* stamp value. This method may be useful for recovery after
* errors.
*
- * @return true if the lock was held, else false
+ * @return {@code true} if the lock was held, else false
*/
public boolean tryUnlockWrite() {
long s; WNode h;
@@ -733,7 +726,7 @@ public class StampedLock implements java
* requiring a stamp value. This method may be useful for recovery
* after errors.
*
- * @return true if the read lock was held, else false
+ * @return {@code true} if the read lock was held, else false
*/
public boolean tryUnlockRead() {
long s, m; WNode h;
@@ -751,30 +744,66 @@ public class StampedLock implements java
return false;
}
+ // status monitoring methods
+
+ /**
+ * Returns combined state-held and overflow read count for given
+ * state s.
+ */
+ private int getReadLockCount(long s) {
+ long readers;
+ if ((readers = s & RBITS) >= RFULL)
+ readers = RFULL + readerOverflow;
+ return (int) readers;
+ }
+
/**
- * Returns true if the lock is currently held exclusively.
+ * Returns {@code true} if the lock is currently held exclusively.
*
- * @return true if the lock is currently held exclusively
+ * @return {@code true} if the lock is currently held exclusively
*/
public boolean isWriteLocked() {
return (state & WBIT) != 0L;
}
/**
- * Returns true if the lock is currently held non-exclusively.
+ * Returns {@code true} if the lock is currently held non-exclusively.
*
- * @return true if the lock is currently held non-exclusively
+ * @return {@code true} if the lock is currently held non-exclusively
*/
public boolean isReadLocked() {
return (state & RBITS) != 0L;
}
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
- state = ORIGIN; // reset to unlocked state
+ /**
+ * Queries the number of read locks held for this lock. This
+ * method is designed for use in monitoring system state, not for
+ * synchronization control.
+ * @return the number of read locks held
+ */
+ public int getReadLockCount() {
+ return getReadLockCount(state);
+ }
+
+ /**
+ * Returns a string identifying this lock, as well as its lock
+ * state. The state, in brackets, includes the String {@code
+ * "Unlocked"} or the String {@code "Write-locked"} or the String
+ * {@code "Read-locks:"} followed by the current number of
+ * read-locks held.
+ *
+ * @return a string identifying this lock, as well as its lock state
+ */
+ public String toString() {
+ long s = state;
+ return super.toString() +
+ ((s & ABITS) == 0L ? "[Unlocked]" :
+ (s & WBIT) != 0L ? "[Write-locked]" :
+ "[Read-locks:" + getReadLockCount(s) + "]");
}
+ // views
+
/**
* Returns a plain {@link Lock} view of this StampedLock in which
* the {@link Lock#lock} method is mapped to {@link #readLock},
@@ -889,6 +918,12 @@ public class StampedLock implements java
}
}
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ s.defaultReadObject();
+ state = ORIGIN; // reset to unlocked state
+ }
+
// internals
/**
@@ -896,10 +931,11 @@ public class StampedLock implements java
* access bits value to RBITS, indicating hold of spinlock,
* then updating, then releasing.
*
- * @param s, assumed that (s & ABITS) >= RFULL
+ * @param s a reader overflow stamp: (s & ABITS) >= RFULL
* @return new stamp on success, else zero
*/
private long tryIncReaderOverflow(long s) {
+ // assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
++readerOverflow;
@@ -916,10 +952,11 @@ public class StampedLock implements java
/**
* Tries to decrement readerOverflow.
*
- * @param s, assumed that (s & ABITS) >= RFULL
+ * @param s a reader overflow stamp: (s & ABITS) >= RFULL
* @return new stamp on success, else zero
*/
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;
@@ -955,17 +992,8 @@ public class StampedLock implements java
if (t.status <= 0)
q = t;
}
- if (q != null) {
- for (WNode r = q;;) { // release co-waiters too
- if ((w = r.thread) != null) {
- r.thread = null;
- U.unpark(w);
- }
- if ((r = q.cowait) == null)
- break;
- U.compareAndSwapObject(q, WCOWAIT, r, r.cowait);
- }
- }
+ if (q != null && (w = q.thread) != null)
+ U.unpark(w);
}
}
@@ -981,22 +1009,22 @@ public class StampedLock implements java
private long acquireWrite(boolean interruptible, long deadline) {
WNode node = null, p;
for (int spins = -1;;) { // spin while enqueuing
- long s, ns;
- if (((s = state) & ABITS) == 0L) {
+ 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 = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {
if (ThreadLocalRandom.current().nextInt() >= 0)
--spins;
}
else if ((p = wtail) == null) { // initialize queue
- WNode h = new WNode(WMODE, null);
- if (U.compareAndSwapObject(this, WHEAD, null, h))
- wtail = h;
+ WNode hd = new WNode(WMODE, null);
+ if (U.compareAndSwapObject(this, WHEAD, null, hd))
+ wtail = hd;
}
- else if (spins < 0)
- spins = (p == whead) ? SPINS : 0;
else if (node == null)
node = new WNode(WMODE, p);
else if (node.prev != p)
@@ -1007,14 +1035,18 @@ public class StampedLock implements java
}
}
- for (int spins = SPINS;;) {
- WNode np, pp; int ps; long s, ns; Thread w;
- while ((np = node.prev) != p && np != null)
- (p = np).next = node; // stale
- if (whead == 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 s, ns;
if (((s = state) & ABITS) == 0L) {
- if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) {
+ if (U.compareAndSwapLong(this, STATE, s,
+ ns = s + WBIT)) {
whead = node;
node.prev = null;
return ns;
@@ -1024,30 +1056,45 @@ public class StampedLock implements java
--k <= 0)
break;
}
- if (spins < MAX_HEAD_SPINS)
- spins <<= 1;
}
- 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 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);
}
}
- 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);
- node.thread = Thread.currentThread();
- if (node.prev == p && p.status == WAITING && // recheck
- (p != whead || (state & ABITS) != 0L))
- U.park(false, time);
- node.thread = null;
- if (interruptible && Thread.interrupted())
- return cancelWaiter(node, node, true);
+ 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);
+ }
}
}
}
@@ -1062,132 +1109,159 @@ public class StampedLock implements java
* @return next state, or INTERRUPTED
*/
private long acquireRead(boolean interruptible, long deadline) {
- WNode node = null, group = null, p;
+ WNode node = null, p;
for (int spins = -1;;) {
- for (;;) {
- long s, m, ns; WNode h, q; Thread w; // anti-barging guard
- if (group == null && (h = whead) != null &&
- (q = h.next) != null && q.mode != RMODE)
- break;
- if ((m = (s = state) & ABITS) < RFULL ?
- U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
- (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
- if (group != null) { // help release others
- for (WNode r = group;;) {
- if ((w = r.thread) != null) {
- r.thread = null;
- U.unpark(w);
+ WNode h;
+ if ((h = whead) == (p = wtail)) {
+ for (long m, s, ns;;) {
+ 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 (ThreadLocalRandom.current().nextInt() >= 0)
+ --spins;
+ }
+ else {
+ if (spins == 0) {
+ WNode nh = whead, np = wtail;
+ if ((nh == h && np == p) || (h = nh) != (p = np))
+ break;
}
- if ((r = group.cowait) == null)
- break;
- U.compareAndSwapObject(group, WCOWAIT, r, r.cowait);
+ spins = SPINS;
}
}
- return ns;
}
- if (m >= WBIT)
- break;
}
- if (spins > 0) {
- if (ThreadLocalRandom.current().nextInt() >= 0)
- --spins;
- }
- else if ((p = wtail) == null) {
- WNode h = new WNode(WMODE, null);
- if (U.compareAndSwapObject(this, WHEAD, null, h))
- wtail = h;
+ if (p == null) { // initialize queue
+ WNode hd = new WNode(WMODE, null);
+ if (U.compareAndSwapObject(this, WHEAD, null, hd))
+ wtail = hd;
}
- else if (spins < 0)
- spins = (p == whead) ? SPINS : 0;
else if (node == null)
- node = new WNode(WMODE, p);
- else if (node.prev != p)
- node.prev = p;
- else if (p.mode == RMODE && p != whead) {
- WNode pp = p.prev; // become co-waiter with group p
- if (pp != null && p == wtail &&
- U.compareAndSwapObject(p, WCOWAIT,
- node.cowait = p.cowait, node)) {
- node.thread = Thread.currentThread();
- for (long time;;) {
- if (interruptible && Thread.interrupted())
- return cancelWaiter(node, p, true);
+ node = new WNode(RMODE, p);
+ else if (h == p || p.mode != RMODE) {
+ if (node.prev != p)
+ node.prev = p;
+ else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+ p.next = node;
+ break;
+ }
+ }
+ 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) // help release
+ U.unpark(w);
+ 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;
+ 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);
- if (node.thread == null)
- break;
- if (p.prev != pp || p.status == CANCELLED ||
- p == whead || p.prev != pp) {
- node.thread = null;
- break;
- }
- if (node.thread == null) // must recheck
- break;
- U.park(false, time);
+ Thread wt = Thread.currentThread();
+ U.putObject(wt, PARKBLOCKER, this);
+ node.thread = wt;
+ 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);
}
- group = p;
}
- node = null; // throw away
- }
- else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
- p.next = node;
- break;
}
}
- for (int spins = SPINS;;) {
- WNode np, pp, r; int ps; long m, s, ns; Thread w;
- while ((np = node.prev) != p && np != null)
- (p = np).next = node;
- if (whead == p) {
- for (int k = spins;;) {
- if ((m = (s = state) & ABITS) != WBIT) {
- if (m < RFULL ?
- U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT):
- (ns = tryIncReaderOverflow(s)) != 0L) {
- whead = node;
- node.prev = null;
- while ((r = node.cowait) != null) {
- if (U.compareAndSwapObject(node, WCOWAIT,
- r, r.cowait) &&
- (w = r.thread) != null) {
- r.thread = null;
- U.unpark(w); // release co-waiter
- }
- }
- return ns;
+ 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) :
+ (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 (ThreadLocalRandom.current().nextInt() >= 0 &&
- --k <= 0)
+ else if (m >= WBIT &&
+ ThreadLocalRandom.current().nextInt() >= 0 && --k <= 0)
break;
}
- if (spins < MAX_HEAD_SPINS)
- spins <<= 1;
}
- 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 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);
}
}
- else {
- long time;
- if (deadline == 0L)
- time = 0L;
- else if ((time = deadline - System.nanoTime()) <= 0L)
- return cancelWaiter(node, node, false);
- node.thread = Thread.currentThread();
- if (node.prev == p && p.status == WAITING &&
- (p != whead || (state & ABITS) != WBIT))
- U.park(false, time);
- node.thread = null;
- if (interruptible && Thread.interrupted())
- return cancelWaiter(node, node, true);
+ 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;
+ 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);
+ }
}
}
}
@@ -1204,7 +1278,7 @@ public class StampedLock implements java
* internal documentation).
*
* @param node if nonnull, the waiter
- * @param group, either node or the group node is cowaiting with
+ * @param group either node or the group node is cowaiting with
* @param interrupted if already interrupted
* @return INTERRUPTED if interrupted or Thread.interrupted, else zero
*/
@@ -1212,22 +1286,19 @@ public class StampedLock implements java
if (node != null && group != null) {
Thread w;
node.status = CANCELLED;
- node.thread = null;
// unsplice cancelled nodes from group
for (WNode p = group, q; (q = p.cowait) != null;) {
- if (q.status == CANCELLED)
- U.compareAndSwapObject(p, WNEXT, q, q.next);
+ if (q.status == CANCELLED) {
+ U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
+ p = group; // restart
+ }
else
p = q;
}
if (group == node) {
- WNode r; // detach and wake up uncancelled co-waiters
- while ((r = node.cowait) != null) {
- if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) &&
- (w = r.thread) != null) {
- r.thread = null;
- U.unpark(w);
- }
+ 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
@@ -1286,6 +1357,7 @@ public class StampedLock implements java
private static final long WNEXT;
private static final long WSTATUS;
private static final long WCOWAIT;
+ private static final long PARKBLOCKER;
static {
try {
@@ -1304,6 +1376,9 @@ public class StampedLock implements java
(wk.getDeclaredField("next"));
WCOWAIT = U.objectFieldOffset
(wk.getDeclaredField("cowait"));
+ Class> tk = Thread.class;
+ PARKBLOCKER = U.objectFieldOffset
+ (tk.getDeclaredField("parkBlocker"));
} catch (Exception e) {
throw new Error(e);