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.34 by jsr166, Mon Jan 28 17:23:04 2013 UTC vs.
Revision 1.37 by jsr166, Sun Jul 14 19:55:05 2013 UTC

# Line 5 | Line 5
5   */
6  
7   package jsr166e;
8
9 import java.util.concurrent.ThreadLocalRandom;
8   import java.util.concurrent.TimeUnit;
9   import java.util.concurrent.locks.Lock;
10   import java.util.concurrent.locks.Condition;
# Line 119 | Line 117 | import java.util.concurrent.locks.LockSu
117   *     }
118   *   }
119   *
120 < *   double distanceFromOriginV1() { // A read-only method
121 < *     long stamp;
122 < *     if ((stamp = sl.tryOptimisticRead()) != 0L) { // optimistic
123 < *       double currentX = x;
124 < *       double currentY = y;
125 < *       if (sl.validate(stamp))
126 < *         return Math.sqrt(currentX * currentX + currentY * currentY);
127 < *     }
128 < *     stamp = sl.readLock(); // fall back to read lock
129 < *     try {
130 < *       double currentX = x;
133 < *       double currentY = y;
134 < *         return Math.sqrt(currentX * currentX + currentY * currentY);
135 < *     } finally {
136 < *       sl.unlockRead(stamp);
137 < *     }
138 < *   }
139 < *
140 < *   double distanceFromOriginV2() { // combines code paths
141 < *     double currentX = 0.0, currentY = 0.0;
142 < *     for (long stamp = sl.tryOptimisticRead(); ; stamp = sl.readLock()) {
143 < *       try {
144 < *         currentX = x;
145 < *         currentY = y;
146 < *       } finally {
147 < *         if (sl.tryConvertToOptimisticRead(stamp) != 0L) // unlock or validate
148 < *           break;
149 < *       }
120 > *   double distanceFromOrigin() { // A read-only method
121 > *     long stamp = sl.tryOptimisticRead();
122 > *     double currentX = x, currentY = y;
123 > *     if (!sl.validate(stamp)) {
124 > *        stamp = sl.readLock();
125 > *        try {
126 > *          currentX = x;
127 > *          currentY = y;
128 > *        } finally {
129 > *           sl.unlockRead(stamp);
130 > *        }
131   *     }
132   *     return Math.sqrt(currentX * currentX + currentY * currentY);
133   *   }
# Line 358 | Line 339 | public class StampedLock implements java
339       * Behavior under timeout and interruption matches that specified
340       * for method {@link Lock#tryLock(long,TimeUnit)}.
341       *
342 +     * @param time the maximum time to wait for the lock
343 +     * @param unit the time unit of the {@code time} argument
344       * @return a stamp that can be used to unlock or convert mode,
345       * or zero if the lock is not available
346       * @throws InterruptedException if the current thread is interrupted
# Line 437 | Line 420 | public class StampedLock implements java
420       * Behavior under timeout and interruption matches that specified
421       * for method {@link Lock#tryLock(long,TimeUnit)}.
422       *
423 +     * @param time the maximum time to wait for the lock
424 +     * @param unit the time unit of the {@code time} argument
425       * @return a stamp that can be used to unlock or convert mode,
426       * or zero if the lock is not available
427       * @throws InterruptedException if the current thread is interrupted
# Line 502 | Line 487 | public class StampedLock implements java
487       * obtained from {@link #tryOptimisticRead} or a locking method
488       * for this lock has no defined effect or result.
489       *
490 <     * @return true if the lock has not been exclusively acquired
490 >     * @param stamp a stamp
491 >     * @return {@code true} if the lock has not been exclusively acquired
492       * since issuance of the given stamp; else false
493       */
494      public boolean validate(long stamp) {
# Line 715 | Line 701 | public class StampedLock implements java
701       * stamp value. This method may be useful for recovery after
702       * errors.
703       *
704 <     * @return true if the lock was held, else false
704 >     * @return {@code true} if the lock was held, else false
705       */
706      public boolean tryUnlockWrite() {
707          long s; WNode h;
# Line 733 | Line 719 | public class StampedLock implements java
719       * requiring a stamp value. This method may be useful for recovery
720       * after errors.
721       *
722 <     * @return true if the read lock was held, else false
722 >     * @return {@code true} if the read lock was held, else false
723       */
724      public boolean tryUnlockRead() {
725          long s, m; WNode h;
# Line 751 | Line 737 | public class StampedLock implements java
737          return false;
738      }
739  
740 +    // status monitoring methods
741 +
742      /**
743 <     * Returns true if the lock is currently held exclusively.
743 >     * Returns combined state-held and overflow read count for given
744 >     * state s.
745 >     */
746 >    private int getReadLockCount(long s) {
747 >        long readers;
748 >        if ((readers = s & RBITS) >= RFULL)
749 >            readers = RFULL + readerOverflow;
750 >        return (int) readers;
751 >    }
752 >
753 >    /**
754 >     * Returns {@code true} if the lock is currently held exclusively.
755       *
756 <     * @return true if the lock is currently held exclusively
756 >     * @return {@code true} if the lock is currently held exclusively
757       */
758      public boolean isWriteLocked() {
759          return (state & WBIT) != 0L;
760      }
761  
762      /**
763 <     * Returns true if the lock is currently held non-exclusively.
763 >     * Returns {@code true} if the lock is currently held non-exclusively.
764       *
765 <     * @return true if the lock is currently held non-exclusively
765 >     * @return {@code true} if the lock is currently held non-exclusively
766       */
767      public boolean isReadLocked() {
768          return (state & RBITS) != 0L;
769      }
770  
771 <    private void readObject(java.io.ObjectInputStream s)
772 <        throws java.io.IOException, ClassNotFoundException {
773 <        s.defaultReadObject();
774 <        state = ORIGIN; // reset to unlocked state
771 >    /**
772 >     * Queries the number of read locks held for this lock. This
773 >     * method is designed for use in monitoring system state, not for
774 >     * synchronization control.
775 >     * @return the number of read locks held
776 >     */
777 >    public int getReadLockCount() {
778 >        return getReadLockCount(state);
779      }
780  
781      /**
782 +     * Returns a string identifying this lock, as well as its lock
783 +     * state.  The state, in brackets, includes the String {@code
784 +     * "Unlocked"} or the String {@code "Write-locked"} or the String
785 +     * {@code "Read-locks:"} followed by the current number of
786 +     * read-locks held.
787 +     *
788 +     * @return a string identifying this lock, as well as its lock state
789 +     */
790 +    public String toString() {
791 +        long s = state;
792 +        return super.toString() +
793 +            ((s & ABITS) == 0L ? "[Unlocked]" :
794 +             (s & WBIT) != 0L ? "[Write-locked]" :
795 +             "[Read-locks:" + getReadLockCount(s) + "]");
796 +    }
797 +
798 +    // views
799 +
800 +    /**
801       * Returns a plain {@link Lock} view of this StampedLock in which
802       * the {@link Lock#lock} method is mapped to {@link #readLock},
803       * and similarly for other methods. The returned Lock does not
# Line 889 | Line 911 | public class StampedLock implements java
911          }
912      }
913  
914 +    private void readObject(java.io.ObjectInputStream s)
915 +        throws java.io.IOException, ClassNotFoundException {
916 +        s.defaultReadObject();
917 +        state = ORIGIN; // reset to unlocked state
918 +    }
919 +
920      // internals
921  
922      /**
# Line 896 | Line 924 | public class StampedLock implements java
924       * access bits value to RBITS, indicating hold of spinlock,
925       * then updating, then releasing.
926       *
927 <     * @param s, assumed that (s & ABITS) >= RFULL
927 >     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
928       * @return new stamp on success, else zero
929       */
930      private long tryIncReaderOverflow(long s) {
931 +        // assert (s & ABITS) >= RFULL;
932          if ((s & ABITS) == RFULL) {
933              if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
934                  ++readerOverflow;
# Line 916 | Line 945 | public class StampedLock implements java
945      /**
946       * Tries to decrement readerOverflow.
947       *
948 <     * @param s, assumed that (s & ABITS) >= RFULL
948 >     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
949       * @return new stamp on success, else zero
950       */
951      private long tryDecReaderOverflow(long s) {
952 +        // assert (s & ABITS) >= RFULL;
953          if ((s & ABITS) == RFULL) {
954              if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
955                  int r; long next;
# Line 1041 | Line 1071 | public class StampedLock implements java
1071                      time = 0L;
1072                  else if ((time = deadline - System.nanoTime()) <= 0L)
1073                      return cancelWaiter(node, node, false);
1074 <                node.thread = Thread.currentThread();
1074 >                Thread wt = Thread.currentThread();
1075 >                U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park
1076 >                node.thread = wt;
1077                  if (node.prev == p && p.status == WAITING && // recheck
1078                      (p != whead || (state & ABITS) != 0L))
1079                      U.park(false, time);
1080                  node.thread = null;
1081 +                U.putObject(wt, PARKBLOCKER, null);
1082                  if (interruptible && Thread.interrupted())
1083                      return cancelWaiter(node, node, true);
1084              }
# Line 1110 | Line 1143 | public class StampedLock implements java
1143                                             node.cowait = p.cowait, node)) {
1144                      node.thread = Thread.currentThread();
1145                      for (long time;;) {
1113                        if (interruptible && Thread.interrupted())
1114                            return cancelWaiter(node, p, true);
1146                          if (deadline == 0L)
1147                              time = 0L;
1148                          else if ((time = deadline - System.nanoTime()) <= 0L)
# Line 1123 | Line 1154 | public class StampedLock implements java
1154                              node.thread = null;
1155                              break;
1156                          }
1157 +                        Thread wt = Thread.currentThread();
1158 +                        U.putObject(wt, PARKBLOCKER, this);
1159                          if (node.thread == null) // must recheck
1160                              break;
1161                          U.park(false, time);
1162 +                        U.putObject(wt, PARKBLOCKER, null);
1163 +                        if (interruptible && Thread.interrupted())
1164 +                            return cancelWaiter(node, p, true);
1165                      }
1166                      group = p;
1167                  }
# Line 1181 | Line 1217 | public class StampedLock implements java
1217                      time = 0L;
1218                  else if ((time = deadline - System.nanoTime()) <= 0L)
1219                      return cancelWaiter(node, node, false);
1220 <                node.thread = Thread.currentThread();
1220 >                Thread wt = Thread.currentThread();
1221 >                U.putObject(wt, PARKBLOCKER, this);
1222 >                node.thread = wt;
1223                  if (node.prev == p && p.status == WAITING &&
1224                      (p != whead || (state & ABITS) != WBIT))
1225                      U.park(false, time);
1226                  node.thread = null;
1227 +                U.putObject(wt, PARKBLOCKER, null);
1228                  if (interruptible && Thread.interrupted())
1229                      return cancelWaiter(node, node, true);
1230              }
# Line 1204 | Line 1243 | public class StampedLock implements java
1243       * internal documentation).
1244       *
1245       * @param node if nonnull, the waiter
1246 <     * @param group, either node or the group node is cowaiting with
1246 >     * @param group either node or the group node is cowaiting with
1247       * @param interrupted if already interrupted
1248       * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
1249       */
# Line 1286 | Line 1325 | public class StampedLock implements java
1325      private static final long WNEXT;
1326      private static final long WSTATUS;
1327      private static final long WCOWAIT;
1328 +    private static final long PARKBLOCKER;
1329  
1330      static {
1331          try {
# Line 1304 | Line 1344 | public class StampedLock implements java
1344                  (wk.getDeclaredField("next"));
1345              WCOWAIT = U.objectFieldOffset
1346                  (wk.getDeclaredField("cowait"));
1347 +            Class<?> tk = Thread.class;
1348 +            PARKBLOCKER = U.objectFieldOffset
1349 +                (tk.getDeclaredField("parkBlocker"));
1350  
1351          } catch (Exception e) {
1352              throw new Error(e);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines