src/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java

Print this page




  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/licenses/publicdomain
  34  */
  35 
  36 package java.util.concurrent.atomic;
  37 
  38 /**
  39  * An {@code AtomicStampedReference} maintains an object reference
  40  * along with an integer "stamp", that can be updated atomically.
  41  *
  42  * <p> Implementation note. This implementation maintains stamped
  43  * references by creating internal objects representing "boxed"
  44  * [reference, integer] pairs.
  45  *
  46  * @since 1.5
  47  * @author Doug Lea
  48  * @param <V> The type of object referred to by this reference
  49  */
  50 public class AtomicStampedReference<V>  {
  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;

  57         }


  58     }

  59 
  60     private final AtomicReference<ReferenceIntegerPair<V>>  atomicRef;
  61 
  62     /**
  63      * Creates a new {@code AtomicStampedReference} with the given
  64      * initial values.
  65      *
  66      * @param initialRef the initial reference
  67      * @param initialStamp the initial stamp
  68      */
  69     public AtomicStampedReference(V initialRef, int initialStamp) {
  70         atomicRef = new AtomicReference<ReferenceIntegerPair<V>>
  71             (new ReferenceIntegerPair<V>(initialRef, initialStamp));
  72     }
  73 
  74     /**
  75      * Returns the current value of the reference.
  76      *
  77      * @return the current value of the reference
  78      */
  79     public V getReference() {
  80         return atomicRef.get().reference;
  81     }
  82 
  83     /**
  84      * Returns the current value of the stamp.
  85      *
  86      * @return the current value of the stamp
  87      */
  88     public int getStamp() {
  89         return atomicRef.get().integer;
  90     }
  91 
  92     /**
  93      * Returns the current values of both the reference and the stamp.
  94      * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
  95      *
  96      * @param stampHolder an array of size of at least one.  On return,
  97      * {@code stampholder[0]} will hold the value of the stamp.
  98      * @return the current value of the reference
  99      */
 100     public V get(int[] stampHolder) {
 101         ReferenceIntegerPair<V> p = atomicRef.get();
 102         stampHolder[0] = p.integer;
 103         return p.reference;
 104     }
 105 
 106     /**
 107      * Atomically sets the value of both the reference and stamp
 108      * to the given update values if the
 109      * current reference is {@code ==} to the expected reference
 110      * and the current stamp is equal to the expected stamp.
 111      *
 112      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 113      * and does not provide ordering guarantees, so is only rarely an
 114      * appropriate alternative to {@code compareAndSet}.
 115      *
 116      * @param expectedReference the expected value of the reference
 117      * @param newReference the new value for the reference
 118      * @param expectedStamp the expected value of the stamp
 119      * @param newStamp the new value for the stamp
 120      * @return true if successful
 121      */
 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)));
 134     }
 135 
 136     /**
 137      * Atomically sets the value of both the reference and stamp
 138      * to the given update values if the
 139      * current reference is {@code ==} to the expected reference
 140      * and the current stamp is equal to the expected stamp.
 141      *
 142      * @param expectedReference the expected value of the reference
 143      * @param newReference the new value for the reference
 144      * @param expectedStamp the expected value of the stamp
 145      * @param newStamp the new value for the stamp
 146      * @return true if successful
 147      */
 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 &&

 155             ((newReference == current.reference &&
 156               newStamp == current.integer) ||
 157              atomicRef.compareAndSet(current,
 158                                      new ReferenceIntegerPair<V>(newReference,
 159                                                               newStamp)));
 160     }
 161 
 162 
 163     /**
 164      * Unconditionally sets the value of both the reference and stamp.
 165      *
 166      * @param newReference the new value for the reference
 167      * @param newStamp the new value for the stamp
 168      */
 169     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));
 173     }
 174 
 175     /**
 176      * Atomically sets the value of the stamp to the given update value
 177      * if the current reference is {@code ==} to the expected
 178      * reference.  Any given invocation of this operation may fail
 179      * (return {@code false}) spuriously, but repeated invocation
 180      * when the current value holds the expected value and no other
 181      * thread is also attempting to set the value will eventually
 182      * succeed.
 183      *
 184      * @param expectedReference the expected value of the reference
 185      * @param newStamp the new value for the stamp
 186      * @return true if successful
 187      */
 188     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)));
 195     }






















 196 }


  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/licenses/publicdomain
  34  */
  35 
  36 package java.util.concurrent.atomic;
  37 
  38 /**
  39  * An {@code AtomicStampedReference} maintains an object reference
  40  * along with an integer "stamp", that can be updated atomically.
  41  *
  42  * <p>Implementation note: This implementation maintains stamped
  43  * references by creating internal objects representing "boxed"
  44  * [reference, integer] pairs.
  45  *
  46  * @since 1.5
  47  * @author Doug Lea
  48  * @param <V> The type of object referred to by this reference
  49  */
  50 public class AtomicStampedReference<V> {
  51 
  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;
  58         }
  59         static <T> Pair<T> of(T reference, int stamp) {
  60             return new Pair<T>(reference, stamp);
  61         }
  62     }
  63 
  64     private volatile Pair<V> pair;
  65 
  66     /**
  67      * Creates a new {@code AtomicStampedReference} with the given
  68      * initial values.
  69      *
  70      * @param initialRef the initial reference
  71      * @param initialStamp the initial stamp
  72      */
  73     public AtomicStampedReference(V initialRef, int initialStamp) {
  74         pair = Pair.of(initialRef, initialStamp);

  75     }
  76 
  77     /**
  78      * Returns the current value of the reference.
  79      *
  80      * @return the current value of the reference
  81      */
  82     public V getReference() {
  83         return pair.reference;
  84     }
  85 
  86     /**
  87      * Returns the current value of the stamp.
  88      *
  89      * @return the current value of the stamp
  90      */
  91     public int getStamp() {
  92         return pair.stamp;
  93     }
  94 
  95     /**
  96      * Returns the current values of both the reference and the stamp.
  97      * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
  98      *
  99      * @param stampHolder an array of size of at least one.  On return,
 100      * {@code stampholder[0]} will hold the value of the stamp.
 101      * @return the current value of the reference
 102      */
 103     public V get(int[] stampHolder) {
 104         Pair<V> pair = this.pair;
 105         stampHolder[0] = pair.stamp;
 106         return pair.reference;
 107     }
 108 
 109     /**
 110      * Atomically sets the value of both the reference and stamp
 111      * to the given update values if the
 112      * current reference is {@code ==} to the expected reference
 113      * and the current stamp is equal to the expected stamp.
 114      *
 115      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 116      * and does not provide ordering guarantees, so is only rarely an
 117      * appropriate alternative to {@code compareAndSet}.
 118      *
 119      * @param expectedReference the expected value of the reference
 120      * @param newReference the new value for the reference
 121      * @param expectedStamp the expected value of the stamp
 122      * @param newStamp the new value for the stamp
 123      * @return true if successful
 124      */
 125     public boolean weakCompareAndSet(V   expectedReference,
 126                                      V   newReference,
 127                                      int expectedStamp,
 128                                      int newStamp) {
 129         return compareAndSet(expectedReference, newReference,
 130                              expectedStamp, newStamp);






 131     }
 132 
 133     /**
 134      * Atomically sets the value of both the reference and stamp
 135      * to the given update values if the
 136      * current reference is {@code ==} to the expected reference
 137      * and the current stamp is equal to the expected stamp.
 138      *
 139      * @param expectedReference the expected value of the reference
 140      * @param newReference the new value for the reference
 141      * @param expectedStamp the expected value of the stamp
 142      * @param newStamp the new value for the stamp
 143      * @return true if successful
 144      */
 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 &&
 153             ((newReference == current.reference &&
 154               newStamp == current.stamp) ||
 155              casPair(current, Pair.of(newReference, newStamp)));


 156     }
 157 
 158 
 159     /**
 160      * Unconditionally sets the value of both the reference and stamp.
 161      *
 162      * @param newReference the new value for the reference
 163      * @param newStamp the new value for the stamp
 164      */
 165     public void set(V newReference, int newStamp) {
 166         Pair<V> current = pair;
 167         if (newReference != current.reference || newStamp != current.stamp)
 168             this.pair = Pair.of(newReference, newStamp);
 169     }
 170 
 171     /**
 172      * Atomically sets the value of the stamp to the given update value
 173      * if the current reference is {@code ==} to the expected
 174      * reference.  Any given invocation of this operation may fail
 175      * (return {@code false}) spuriously, but repeated invocation
 176      * when the current value holds the expected value and no other
 177      * thread is also attempting to set the value will eventually
 178      * succeed.
 179      *
 180      * @param expectedReference the expected value of the reference
 181      * @param newStamp the new value for the stamp
 182      * @return true if successful
 183      */
 184     public boolean attemptStamp(V expectedReference, int newStamp) {
 185         Pair<V> current = pair;
 186         return
 187             expectedReference == current.reference &&
 188             (newStamp == current.stamp ||
 189              casPair(current, Pair.of(expectedReference, newStamp)));

 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     }
 213 }