Print this page


Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java
          +++ new/src/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java
↓ open down ↓ 31 lines elided ↑ open up ↑
  32   32   * Expert Group and released to the public domain, as explained at
  33   33   * http://creativecommons.org/licenses/publicdomain
  34   34   */
  35   35  
  36   36  package java.util.concurrent.atomic;
  37   37  
  38   38  /**
  39   39   * An {@code AtomicStampedReference} maintains an object reference
  40   40   * along with an integer "stamp", that can be updated atomically.
  41   41   *
  42      - * <p> Implementation note. This implementation maintains stamped
       42 + * <p>Implementation note: This implementation maintains stamped
  43   43   * references by creating internal objects representing "boxed"
  44   44   * [reference, integer] pairs.
  45   45   *
  46   46   * @since 1.5
  47   47   * @author Doug Lea
  48   48   * @param <V> The type of object referred to by this reference
  49   49   */
  50      -public class AtomicStampedReference<V>  {
       50 +public class AtomicStampedReference<V> {
  51   51  
  52      -    private static class ReferenceIntegerPair<T> {
  53      -        private final T reference;
  54      -        private final int integer;
  55      -        ReferenceIntegerPair(T r, int i) {
  56      -            reference = r; integer = i;
       52 +    private static class Pair<T> {
       53 +        final T reference;
       54 +        final int stamp;
       55 +        private Pair(T reference, int stamp) {
       56 +            this.reference = reference;
       57 +            this.stamp = stamp;
  57   58          }
       59 +        static <T> Pair<T> of(T reference, int stamp) {
       60 +            return new Pair<T>(reference, stamp);
       61 +        }
  58   62      }
  59   63  
  60      -    private final AtomicReference<ReferenceIntegerPair<V>>  atomicRef;
       64 +    private volatile Pair<V> pair;
  61   65  
  62   66      /**
  63   67       * Creates a new {@code AtomicStampedReference} with the given
  64   68       * initial values.
  65   69       *
  66   70       * @param initialRef the initial reference
  67   71       * @param initialStamp the initial stamp
  68   72       */
  69   73      public AtomicStampedReference(V initialRef, int initialStamp) {
  70      -        atomicRef = new AtomicReference<ReferenceIntegerPair<V>>
  71      -            (new ReferenceIntegerPair<V>(initialRef, initialStamp));
       74 +        pair = Pair.of(initialRef, initialStamp);
  72   75      }
  73   76  
  74   77      /**
  75   78       * Returns the current value of the reference.
  76   79       *
  77   80       * @return the current value of the reference
  78   81       */
  79   82      public V getReference() {
  80      -        return atomicRef.get().reference;
       83 +        return pair.reference;
  81   84      }
  82   85  
  83   86      /**
  84   87       * Returns the current value of the stamp.
  85   88       *
  86   89       * @return the current value of the stamp
  87   90       */
  88   91      public int getStamp() {
  89      -        return atomicRef.get().integer;
       92 +        return pair.stamp;
  90   93      }
  91   94  
  92   95      /**
  93   96       * Returns the current values of both the reference and the stamp.
  94   97       * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
  95   98       *
  96   99       * @param stampHolder an array of size of at least one.  On return,
  97  100       * {@code stampholder[0]} will hold the value of the stamp.
  98  101       * @return the current value of the reference
  99  102       */
 100  103      public V get(int[] stampHolder) {
 101      -        ReferenceIntegerPair<V> p = atomicRef.get();
 102      -        stampHolder[0] = p.integer;
 103      -        return p.reference;
      104 +        Pair<V> pair = this.pair;
      105 +        stampHolder[0] = pair.stamp;
      106 +        return pair.reference;
 104  107      }
 105  108  
 106  109      /**
 107  110       * Atomically sets the value of both the reference and stamp
 108  111       * to the given update values if the
 109  112       * current reference is {@code ==} to the expected reference
 110  113       * and the current stamp is equal to the expected stamp.
 111  114       *
 112  115       * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 113  116       * and does not provide ordering guarantees, so is only rarely an
 114  117       * appropriate alternative to {@code compareAndSet}.
 115  118       *
 116  119       * @param expectedReference the expected value of the reference
 117  120       * @param newReference the new value for the reference
 118  121       * @param expectedStamp the expected value of the stamp
 119  122       * @param newStamp the new value for the stamp
 120  123       * @return true if successful
 121  124       */
 122      -    public boolean weakCompareAndSet(V      expectedReference,
 123      -                                     V      newReference,
 124      -                                     int    expectedStamp,
 125      -                                     int    newStamp) {
 126      -        ReferenceIntegerPair<V> current = atomicRef.get();
 127      -        return  expectedReference == current.reference &&
 128      -            expectedStamp == current.integer &&
 129      -            ((newReference == current.reference &&
 130      -              newStamp == current.integer) ||
 131      -             atomicRef.weakCompareAndSet(current,
 132      -                                     new ReferenceIntegerPair<V>(newReference,
 133      -                                                              newStamp)));
      125 +    public boolean weakCompareAndSet(V   expectedReference,
      126 +                                     V   newReference,
      127 +                                     int expectedStamp,
      128 +                                     int newStamp) {
      129 +        return compareAndSet(expectedReference, newReference,
      130 +                             expectedStamp, newStamp);
 134  131      }
 135  132  
 136  133      /**
 137  134       * Atomically sets the value of both the reference and stamp
 138  135       * to the given update values if the
 139  136       * current reference is {@code ==} to the expected reference
 140  137       * and the current stamp is equal to the expected stamp.
 141  138       *
 142  139       * @param expectedReference the expected value of the reference
 143  140       * @param newReference the new value for the reference
 144  141       * @param expectedStamp the expected value of the stamp
 145  142       * @param newStamp the new value for the stamp
 146  143       * @return true if successful
 147  144       */
 148      -    public boolean compareAndSet(V      expectedReference,
 149      -                                 V      newReference,
 150      -                                 int    expectedStamp,
 151      -                                 int    newStamp) {
 152      -        ReferenceIntegerPair<V> current = atomicRef.get();
 153      -        return  expectedReference == current.reference &&
 154      -            expectedStamp == current.integer &&
      145 +    public boolean compareAndSet(V   expectedReference,
      146 +                                 V   newReference,
      147 +                                 int expectedStamp,
      148 +                                 int newStamp) {
      149 +        Pair<V> current = pair;
      150 +        return
      151 +            expectedReference == current.reference &&
      152 +            expectedStamp == current.stamp &&
 155  153              ((newReference == current.reference &&
 156      -              newStamp == current.integer) ||
 157      -             atomicRef.compareAndSet(current,
 158      -                                     new ReferenceIntegerPair<V>(newReference,
 159      -                                                              newStamp)));
      154 +              newStamp == current.stamp) ||
      155 +             casPair(current, Pair.of(newReference, newStamp)));
 160  156      }
 161  157  
 162  158  
 163  159      /**
 164  160       * Unconditionally sets the value of both the reference and stamp.
 165  161       *
 166  162       * @param newReference the new value for the reference
 167  163       * @param newStamp the new value for the stamp
 168  164       */
 169  165      public void set(V newReference, int newStamp) {
 170      -        ReferenceIntegerPair<V> current = atomicRef.get();
 171      -        if (newReference != current.reference || newStamp != current.integer)
 172      -            atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp));
      166 +        Pair<V> current = pair;
      167 +        if (newReference != current.reference || newStamp != current.stamp)
      168 +            this.pair = Pair.of(newReference, newStamp);
 173  169      }
 174  170  
 175  171      /**
 176  172       * Atomically sets the value of the stamp to the given update value
 177  173       * if the current reference is {@code ==} to the expected
 178  174       * reference.  Any given invocation of this operation may fail
 179  175       * (return {@code false}) spuriously, but repeated invocation
 180  176       * when the current value holds the expected value and no other
 181  177       * thread is also attempting to set the value will eventually
 182  178       * succeed.
 183  179       *
 184  180       * @param expectedReference the expected value of the reference
 185  181       * @param newStamp the new value for the stamp
 186  182       * @return true if successful
 187  183       */
 188  184      public boolean attemptStamp(V expectedReference, int newStamp) {
 189      -        ReferenceIntegerPair<V> current = atomicRef.get();
 190      -        return  expectedReference == current.reference &&
 191      -            (newStamp == current.integer ||
 192      -             atomicRef.compareAndSet(current,
 193      -                                     new ReferenceIntegerPair<V>(expectedReference,
 194      -                                                              newStamp)));
      185 +        Pair<V> current = pair;
      186 +        return
      187 +            expectedReference == current.reference &&
      188 +            (newStamp == current.stamp ||
      189 +             casPair(current, Pair.of(expectedReference, newStamp)));
 195  190      }
      191 +
      192 +    // Unsafe mechanics
      193 +
      194 +    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
      195 +    private static final long pairOffset =
      196 +        objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
      197 +
      198 +    private boolean casPair(Pair<V> cmp, Pair<V> val) {
      199 +        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
      200 +    }
      201 +
      202 +    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
      203 +                                  String field, Class<?> klazz) {
      204 +        try {
      205 +            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
      206 +        } catch (NoSuchFieldException e) {
      207 +            // Convert Exception to corresponding Error
      208 +            NoSuchFieldError error = new NoSuchFieldError(field);
      209 +            error.initCause(e);
      210 +            throw error;
      211 +        }
      212 +    }
 196  213  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX