--- jsr166/src/jsr166e/StampedLock.java 2013/01/24 21:35:03 1.31
+++ jsr166/src/jsr166e/StampedLock.java 2013/01/26 01:22:37 1.32
@@ -40,19 +40,20 @@ import java.util.concurrent.locks.LockSu
*
Optimistic Reading. Method {@link #tryOptimisticRead}
* returns a non-zero stamp only if the lock is not currently held
* in write mode. Method {@link #validate} returns true if the lock
- * has not since been acquired in write mode. This mode can be
- * thought of as an extremely weak version of a read-lock, that can
- * be broken by a writer at any time. The use of optimistic mode
- * for short read-only code segments often reduces contention and
- * improves throughput. However, its use is inherently fragile.
- * Optimistic read sections should only read fields and hold them in
- * local variables for later use after validation. Fields read while
- * in optimistic mode may be wildly inconsistent, so usage applies
- * only when you are familiar enough with data representations to
- * check consistency and/or repeatedly 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.
+ * has not been acquired in write mode since obtaining a given
+ * stamp. This mode can be thought of as an extremely weak version
+ * of a read-lock, that can be broken by a writer at any time. The
+ * use of optimistic mode for short read-only code segments often
+ * reduces contention and improves throughput. However, its use is
+ * inherently fragile. Optimistic read sections should only read
+ * fields and hold them in local variables for later use after
+ * validation. Fields read while in optimistic mode may be wildly
+ * inconsistent, so usage applies only when you are familiar enough
+ * with data representations to check consistency and/or repeatedly
+ * 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.
*
*
*
@@ -490,7 +491,9 @@ public class StampedLock implements java
* Returns true if the lock has not been exclusively acquired
* since issuance of the given stamp. Always returns false if the
* stamp is zero. Always returns true if the stamp represents a
- * currently held lock.
+ * currently held lock. Invoking this method with a value not
+ * 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
* since issuance of the given stamp; else false
@@ -1182,6 +1185,104 @@ public class StampedLock implements java
}
}
+ /**
+ * If node non-null, forces cancel status and unsplices it from
+ * queue if possible and wakes up any cowaiters. This is a variant
+ * of cancellation methods in AbstractQueuedSynchronizer (see its
+ * detailed explanation in AQS internal documentation) that more
+ * conservatively wakes up other threads that may have had their
+ * links changed, so as to preserve liveness in the main
+ * signalling methods.
+ *
+ * @param node if nonnull, the waiter
+ * @param group, if nonnull, the group current thread is cowaiting with
+ * @param interrupted if already interrupted
+ * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+ */
+ private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
+ if (node != null) {
+ node.thread = null;
+ node.status = CANCELLED;
+ Thread w; // wake up co-waiters; unsplice cancelled ones
+ for (WNode q, p = (group != null) ? group : node; p != null; ) {
+ if ((q = p.cowait) == null)
+ break;
+ if ((w = q.thread) != null) {
+ q.thread = null;
+ U.unpark(w);
+ }
+ if (q.status == CANCELLED)
+ U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
+ else
+ p = q;
+ }
+ if (group == null) { // unsplice both prev and next links
+ for (WNode pred = node.prev; pred != null; ) {
+ WNode succ, pp; // first unsplice next
+ while ((succ = node.next) == null ||
+ succ.status == CANCELLED) {
+ WNode q = null; // find successor the slow way
+ for (WNode t = wtail; t != null && t != node; t = t.prev)
+ if (t.status != CANCELLED)
+ q = t; // don't link if succ cancelled
+ if (succ == q || // ensure accurate successor
+ U.compareAndSwapObject(node, WNEXT,
+ succ, succ = q)) {
+ if (succ == null && node == wtail)
+ U.compareAndSwapObject(this, WTAIL, node, pred);
+ break;
+ }
+ }
+ if (pred.next == node) // unsplice pred link
+ U.compareAndSwapObject(pred, WNEXT, node, succ);
+ if (succ != null && (w = succ.thread) != null) {
+ succ.thread = null;
+ U.unpark(w); // conservatively wake up new succ
+ }
+ if (pred.status != CANCELLED || (pp = pred.prev) == null)
+ break;
+ node.prev = pp; // repeat in case new pred wrong/cancelled
+ U.compareAndSwapObject(pp, WNEXT, pred, succ);
+ pred = pp;
+ }
+ }
+ }
+ release(whead);
+ return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+ }
+
+ // Unsafe mechanics
+ private static final sun.misc.Unsafe U;
+ private static final long STATE;
+ private static final long WHEAD;
+ private static final long WTAIL;
+ private static final long WNEXT;
+ private static final long WSTATUS;
+ private static final long WCOWAIT;
+
+ static {
+ try {
+ U = getUnsafe();
+ Class> k = StampedLock.class;
+ Class> wk = WNode.class;
+ STATE = U.objectFieldOffset
+ (k.getDeclaredField("state"));
+ WHEAD = U.objectFieldOffset
+ (k.getDeclaredField("whead"));
+ WTAIL = U.objectFieldOffset
+ (k.getDeclaredField("wtail"));
+ WSTATUS = U.objectFieldOffset
+ (wk.getDeclaredField("status"));
+ WNEXT = U.objectFieldOffset
+ (wk.getDeclaredField("next"));
+ WCOWAIT = U.objectFieldOffset
+ (wk.getDeclaredField("cowait"));
+
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
/**
* Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
* Replace with a simple call to Unsafe.getUnsafe when integrating