ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/StampedLock.java
(Generate patch)

Comparing jsr166/src/jsr166e/StampedLock.java (file contents):
Revision 1.31 by dl, Thu Jan 24 21:35:03 2013 UTC vs.
Revision 1.32 by dl, Sat Jan 26 01:22:37 2013 UTC

# Line 40 | Line 40 | import java.util.concurrent.locks.LockSu
40   *  <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
41   *   returns a non-zero stamp only if the lock is not currently held
42   *   in write mode. Method {@link #validate} returns true if the lock
43 < *   has not since been acquired in write mode. This mode can be
44 < *   thought of as an extremely weak version of a read-lock, that can
45 < *   be broken by a writer at any time.  The use of optimistic mode
46 < *   for short read-only code segments often reduces contention and
47 < *   improves throughput.  However, its use is inherently fragile.
48 < *   Optimistic read sections should only read fields and hold them in
49 < *   local variables for later use after validation. Fields read while
50 < *   in optimistic mode may be wildly inconsistent, so usage applies
51 < *   only when you are familiar enough with data representations to
52 < *   check consistency and/or repeatedly invoke method {@code
53 < *   validate()}.  For example, such steps are typically required when
54 < *   first reading an object or array reference, and then accessing
55 < *   one of its fields, elements or methods. </li>
43 > *   has not been acquired in write mode since obtaining a given
44 > *   stamp.  This mode can be thought of as an extremely weak version
45 > *   of a read-lock, that can be broken by a writer at any time.  The
46 > *   use of optimistic mode for short read-only code segments often
47 > *   reduces contention and improves throughput.  However, its use is
48 > *   inherently fragile.  Optimistic read sections should only read
49 > *   fields and hold them in local variables for later use after
50 > *   validation. Fields read while in optimistic mode may be wildly
51 > *   inconsistent, so usage applies only when you are familiar enough
52 > *   with data representations to check consistency and/or repeatedly
53 > *   invoke method {@code validate()}.  For example, such steps are
54 > *   typically required when first reading an object or array
55 > *   reference, and then accessing one of its fields, elements or
56 > *   methods. </li>
57   *
58   * </ul>
59   *
# Line 490 | Line 491 | public class StampedLock implements java
491       * Returns true if the lock has not been exclusively acquired
492       * since issuance of the given stamp. Always returns false if the
493       * stamp is zero. Always returns true if the stamp represents a
494 <     * currently held lock.
494 >     * currently held lock. Invoking this method with a value not
495 >     * obtained from {@link #tryOptimisticRead} or a locking method
496 >     * for this lock has no defined effect or result.
497       *
498       * @return true if the lock has not been exclusively acquired
499       * since issuance of the given stamp; else false
# Line 1182 | Line 1185 | public class StampedLock implements java
1185          }
1186      }
1187  
1188 +    /**
1189 +     * If node non-null, forces cancel status and unsplices it from
1190 +     * queue if possible and wakes up any cowaiters. This is a variant
1191 +     * of cancellation methods in AbstractQueuedSynchronizer (see its
1192 +     * detailed explanation in AQS internal documentation) that more
1193 +     * conservatively wakes up other threads that may have had their
1194 +     * links changed, so as to preserve liveness in the main
1195 +     * signalling methods.
1196 +     *
1197 +     * @param node if nonnull, the waiter
1198 +     * @param group, if nonnull, the group current thread is cowaiting with
1199 +     * @param interrupted if already interrupted
1200 +     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
1201 +     */
1202 +    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
1203 +        if (node != null) {
1204 +            node.thread = null;
1205 +            node.status = CANCELLED;
1206 +            Thread w; // wake up co-waiters; unsplice cancelled ones
1207 +            for (WNode q, p = (group != null) ? group : node; p != null; ) {
1208 +                if ((q = p.cowait) == null)
1209 +                    break;
1210 +                if ((w = q.thread) != null) {
1211 +                    q.thread = null;
1212 +                    U.unpark(w);
1213 +                }
1214 +                if (q.status == CANCELLED)
1215 +                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
1216 +                else
1217 +                    p = q;
1218 +            }
1219 +            if (group == null)  {        // unsplice both prev and next links
1220 +                for (WNode pred = node.prev; pred != null; ) {
1221 +                    WNode succ, pp;      // first unsplice next
1222 +                    while ((succ = node.next) == null ||
1223 +                           succ.status == CANCELLED) {
1224 +                        WNode q = null;  // find successor the slow way
1225 +                        for (WNode t = wtail; t != null && t != node; t = t.prev)
1226 +                            if (t.status != CANCELLED)
1227 +                                q = t;   // don't link if succ cancelled
1228 +                        if (succ == q || // ensure accurate successor
1229 +                            U.compareAndSwapObject(node, WNEXT,
1230 +                                                   succ, succ = q)) {
1231 +                            if (succ == null && node == wtail)
1232 +                                U.compareAndSwapObject(this, WTAIL, node, pred);
1233 +                            break;
1234 +                        }
1235 +                    }
1236 +                    if (pred.next == node) // unsplice pred link
1237 +                        U.compareAndSwapObject(pred, WNEXT, node, succ);
1238 +                    if (succ != null && (w = succ.thread) != null) {
1239 +                        succ.thread = null;
1240 +                        U.unpark(w);      // conservatively wake up new succ
1241 +                    }
1242 +                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
1243 +                        break;
1244 +                    node.prev = pp; // repeat in case new pred wrong/cancelled
1245 +                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
1246 +                    pred = pp;
1247 +                }
1248 +            }
1249 +        }
1250 +        release(whead);
1251 +        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
1252 +    }
1253 +
1254 +    // Unsafe mechanics
1255 +    private static final sun.misc.Unsafe U;
1256 +    private static final long STATE;
1257 +    private static final long WHEAD;
1258 +    private static final long WTAIL;
1259 +    private static final long WNEXT;
1260 +    private static final long WSTATUS;
1261 +    private static final long WCOWAIT;
1262 +
1263 +    static {
1264 +        try {
1265 +            U = getUnsafe();
1266 +            Class<?> k = StampedLock.class;
1267 +            Class<?> wk = WNode.class;
1268 +            STATE = U.objectFieldOffset
1269 +                (k.getDeclaredField("state"));
1270 +            WHEAD = U.objectFieldOffset
1271 +                (k.getDeclaredField("whead"));
1272 +            WTAIL = U.objectFieldOffset
1273 +                (k.getDeclaredField("wtail"));
1274 +            WSTATUS = U.objectFieldOffset
1275 +                (wk.getDeclaredField("status"));
1276 +            WNEXT = U.objectFieldOffset
1277 +                (wk.getDeclaredField("next"));
1278 +            WCOWAIT = U.objectFieldOffset
1279 +                (wk.getDeclaredField("cowait"));
1280 +
1281 +        } catch (Exception e) {
1282 +            throw new Error(e);
1283 +        }
1284 +    }
1285 +
1286      /**
1287       * Returns a sun.misc.Unsafe.  Suitable for use in a 3rd party package.
1288       * Replace with a simple call to Unsafe.getUnsafe when integrating

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines