jdk/src/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java
changeset 7976 f273c0d04215
parent 5506 202f599c92aa
child 9242 ef138d47df58
equal deleted inserted replaced
7975:f0de2d05f34c 7976:f273c0d04215
    37 
    37 
    38 /**
    38 /**
    39  * An {@code AtomicStampedReference} maintains an object reference
    39  * An {@code AtomicStampedReference} maintains an object reference
    40  * along with an integer "stamp", that can be updated atomically.
    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  * references by creating internal objects representing "boxed"
    43  * references by creating internal objects representing "boxed"
    44  * [reference, integer] pairs.
    44  * [reference, integer] pairs.
    45  *
    45  *
    46  * @since 1.5
    46  * @since 1.5
    47  * @author Doug Lea
    47  * @author Doug Lea
    48  * @param <V> The type of object referred to by this reference
    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> {
    52     private static class Pair<T> {
    53         private final T reference;
    53         final T reference;
    54         private final int integer;
    54         final int stamp;
    55         ReferenceIntegerPair(T r, int i) {
    55         private Pair(T reference, int stamp) {
    56             reference = r; integer = i;
    56             this.reference = reference;
       
    57             this.stamp = stamp;
    57         }
    58         }
    58     }
    59         static <T> Pair<T> of(T reference, int stamp) {
    59 
    60             return new Pair<T>(reference, stamp);
    60     private final AtomicReference<ReferenceIntegerPair<V>>  atomicRef;
    61         }
       
    62     }
       
    63 
       
    64     private volatile Pair<V> pair;
    61 
    65 
    62     /**
    66     /**
    63      * Creates a new {@code AtomicStampedReference} with the given
    67      * Creates a new {@code AtomicStampedReference} with the given
    64      * initial values.
    68      * initial values.
    65      *
    69      *
    66      * @param initialRef the initial reference
    70      * @param initialRef the initial reference
    67      * @param initialStamp the initial stamp
    71      * @param initialStamp the initial stamp
    68      */
    72      */
    69     public AtomicStampedReference(V initialRef, int initialStamp) {
    73     public AtomicStampedReference(V initialRef, int initialStamp) {
    70         atomicRef = new AtomicReference<ReferenceIntegerPair<V>>
    74         pair = Pair.of(initialRef, initialStamp);
    71             (new ReferenceIntegerPair<V>(initialRef, initialStamp));
       
    72     }
    75     }
    73 
    76 
    74     /**
    77     /**
    75      * Returns the current value of the reference.
    78      * Returns the current value of the reference.
    76      *
    79      *
    77      * @return the current value of the reference
    80      * @return the current value of the reference
    78      */
    81      */
    79     public V getReference() {
    82     public V getReference() {
    80         return atomicRef.get().reference;
    83         return pair.reference;
    81     }
    84     }
    82 
    85 
    83     /**
    86     /**
    84      * Returns the current value of the stamp.
    87      * Returns the current value of the stamp.
    85      *
    88      *
    86      * @return the current value of the stamp
    89      * @return the current value of the stamp
    87      */
    90      */
    88     public int getStamp() {
    91     public int getStamp() {
    89         return atomicRef.get().integer;
    92         return pair.stamp;
    90     }
    93     }
    91 
    94 
    92     /**
    95     /**
    93      * Returns the current values of both the reference and the stamp.
    96      * Returns the current values of both the reference and the stamp.
    94      * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
    97      * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
    96      * @param stampHolder an array of size of at least one.  On return,
    99      * @param stampHolder an array of size of at least one.  On return,
    97      * {@code stampholder[0]} will hold the value of the stamp.
   100      * {@code stampholder[0]} will hold the value of the stamp.
    98      * @return the current value of the reference
   101      * @return the current value of the reference
    99      */
   102      */
   100     public V get(int[] stampHolder) {
   103     public V get(int[] stampHolder) {
   101         ReferenceIntegerPair<V> p = atomicRef.get();
   104         Pair<V> pair = this.pair;
   102         stampHolder[0] = p.integer;
   105         stampHolder[0] = pair.stamp;
   103         return p.reference;
   106         return pair.reference;
   104     }
   107     }
   105 
   108 
   106     /**
   109     /**
   107      * Atomically sets the value of both the reference and stamp
   110      * Atomically sets the value of both the reference and stamp
   108      * to the given update values if the
   111      * to the given update values if the
   117      * @param newReference the new value for the reference
   120      * @param newReference the new value for the reference
   118      * @param expectedStamp the expected value of the stamp
   121      * @param expectedStamp the expected value of the stamp
   119      * @param newStamp the new value for the stamp
   122      * @param newStamp the new value for the stamp
   120      * @return true if successful
   123      * @return true if successful
   121      */
   124      */
   122     public boolean weakCompareAndSet(V      expectedReference,
   125     public boolean weakCompareAndSet(V   expectedReference,
   123                                      V      newReference,
   126                                      V   newReference,
   124                                      int    expectedStamp,
   127                                      int expectedStamp,
   125                                      int    newStamp) {
   128                                      int newStamp) {
   126         ReferenceIntegerPair<V> current = atomicRef.get();
   129         return compareAndSet(expectedReference, newReference,
   127         return  expectedReference == current.reference &&
   130                              expectedStamp, newStamp);
   128             expectedStamp == current.integer &&
       
   129             ((newReference == current.reference &&
       
   130               newStamp == current.integer) ||
       
   131              atomicRef.weakCompareAndSet(current,
       
   132                                      new ReferenceIntegerPair<V>(newReference,
       
   133                                                               newStamp)));
       
   134     }
   131     }
   135 
   132 
   136     /**
   133     /**
   137      * Atomically sets the value of both the reference and stamp
   134      * Atomically sets the value of both the reference and stamp
   138      * to the given update values if the
   135      * to the given update values if the
   143      * @param newReference the new value for the reference
   140      * @param newReference the new value for the reference
   144      * @param expectedStamp the expected value of the stamp
   141      * @param expectedStamp the expected value of the stamp
   145      * @param newStamp the new value for the stamp
   142      * @param newStamp the new value for the stamp
   146      * @return true if successful
   143      * @return true if successful
   147      */
   144      */
   148     public boolean compareAndSet(V      expectedReference,
   145     public boolean compareAndSet(V   expectedReference,
   149                                  V      newReference,
   146                                  V   newReference,
   150                                  int    expectedStamp,
   147                                  int expectedStamp,
   151                                  int    newStamp) {
   148                                  int newStamp) {
   152         ReferenceIntegerPair<V> current = atomicRef.get();
   149         Pair<V> current = pair;
   153         return  expectedReference == current.reference &&
   150         return
   154             expectedStamp == current.integer &&
   151             expectedReference == current.reference &&
       
   152             expectedStamp == current.stamp &&
   155             ((newReference == current.reference &&
   153             ((newReference == current.reference &&
   156               newStamp == current.integer) ||
   154               newStamp == current.stamp) ||
   157              atomicRef.compareAndSet(current,
   155              casPair(current, Pair.of(newReference, newStamp)));
   158                                      new ReferenceIntegerPair<V>(newReference,
       
   159                                                               newStamp)));
       
   160     }
   156     }
   161 
   157 
   162 
   158 
   163     /**
   159     /**
   164      * Unconditionally sets the value of both the reference and stamp.
   160      * Unconditionally sets the value of both the reference and stamp.
   165      *
   161      *
   166      * @param newReference the new value for the reference
   162      * @param newReference the new value for the reference
   167      * @param newStamp the new value for the stamp
   163      * @param newStamp the new value for the stamp
   168      */
   164      */
   169     public void set(V newReference, int newStamp) {
   165     public void set(V newReference, int newStamp) {
   170         ReferenceIntegerPair<V> current = atomicRef.get();
   166         Pair<V> current = pair;
   171         if (newReference != current.reference || newStamp != current.integer)
   167         if (newReference != current.reference || newStamp != current.stamp)
   172             atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp));
   168             this.pair = Pair.of(newReference, newStamp);
   173     }
   169     }
   174 
   170 
   175     /**
   171     /**
   176      * Atomically sets the value of the stamp to the given update value
   172      * Atomically sets the value of the stamp to the given update value
   177      * if the current reference is {@code ==} to the expected
   173      * if the current reference is {@code ==} to the expected
   184      * @param expectedReference the expected value of the reference
   180      * @param expectedReference the expected value of the reference
   185      * @param newStamp the new value for the stamp
   181      * @param newStamp the new value for the stamp
   186      * @return true if successful
   182      * @return true if successful
   187      */
   183      */
   188     public boolean attemptStamp(V expectedReference, int newStamp) {
   184     public boolean attemptStamp(V expectedReference, int newStamp) {
   189         ReferenceIntegerPair<V> current = atomicRef.get();
   185         Pair<V> current = pair;
   190         return  expectedReference == current.reference &&
   186         return
   191             (newStamp == current.integer ||
   187             expectedReference == current.reference &&
   192              atomicRef.compareAndSet(current,
   188             (newStamp == current.stamp ||
   193                                      new ReferenceIntegerPair<V>(expectedReference,
   189              casPair(current, Pair.of(expectedReference, newStamp)));
   194                                                               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         }
   195     }
   212     }
   196 }
   213 }