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

Print this page

        

*** 37,94 **** /** * An {@code AtomicStampedReference} maintains an object reference * along with an integer "stamp", that can be updated atomically. * ! * <p> Implementation note. This implementation maintains stamped * references by creating internal objects representing "boxed" * [reference, integer] pairs. * * @since 1.5 * @author Doug Lea * @param <V> The type of object referred to by this reference */ public class AtomicStampedReference<V> { ! private static class ReferenceIntegerPair<T> { ! private final T reference; ! private final int integer; ! ReferenceIntegerPair(T r, int i) { ! reference = r; integer = i; } } ! private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; /** * Creates a new {@code AtomicStampedReference} with the given * initial values. * * @param initialRef the initial reference * @param initialStamp the initial stamp */ public AtomicStampedReference(V initialRef, int initialStamp) { ! atomicRef = new AtomicReference<ReferenceIntegerPair<V>> ! (new ReferenceIntegerPair<V>(initialRef, initialStamp)); } /** * Returns the current value of the reference. * * @return the current value of the reference */ public V getReference() { ! return atomicRef.get().reference; } /** * Returns the current value of the stamp. * * @return the current value of the stamp */ public int getStamp() { ! return atomicRef.get().integer; } /** * Returns the current values of both the reference and the stamp. * Typical usage is {@code int[1] holder; ref = v.get(holder); }. --- 37,97 ---- /** * An {@code AtomicStampedReference} maintains an object reference * along with an integer "stamp", that can be updated atomically. * ! * <p>Implementation note: This implementation maintains stamped * references by creating internal objects representing "boxed" * [reference, integer] pairs. * * @since 1.5 * @author Doug Lea * @param <V> The type of object referred to by this reference */ public class AtomicStampedReference<V> { ! private static class Pair<T> { ! final T reference; ! final int stamp; ! private Pair(T reference, int stamp) { ! this.reference = reference; ! this.stamp = stamp; } + static <T> Pair<T> of(T reference, int stamp) { + return new Pair<T>(reference, stamp); } + } ! private volatile Pair<V> pair; /** * Creates a new {@code AtomicStampedReference} with the given * initial values. * * @param initialRef the initial reference * @param initialStamp the initial stamp */ public AtomicStampedReference(V initialRef, int initialStamp) { ! pair = Pair.of(initialRef, initialStamp); } /** * Returns the current value of the reference. * * @return the current value of the reference */ public V getReference() { ! return pair.reference; } /** * Returns the current value of the stamp. * * @return the current value of the stamp */ public int getStamp() { ! return pair.stamp; } /** * Returns the current values of both the reference and the stamp. * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
*** 96,108 **** * @param stampHolder an array of size of at least one. On return, * {@code stampholder[0]} will hold the value of the stamp. * @return the current value of the reference */ public V get(int[] stampHolder) { ! ReferenceIntegerPair<V> p = atomicRef.get(); ! stampHolder[0] = p.integer; ! return p.reference; } /** * Atomically sets the value of both the reference and stamp * to the given update values if the --- 99,111 ---- * @param stampHolder an array of size of at least one. On return, * {@code stampholder[0]} will hold the value of the stamp. * @return the current value of the reference */ public V get(int[] stampHolder) { ! Pair<V> pair = this.pair; ! stampHolder[0] = pair.stamp; ! return pair.reference; } /** * Atomically sets the value of both the reference and stamp * to the given update values if the
*** 121,138 **** */ public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ! ReferenceIntegerPair<V> current = atomicRef.get(); ! return expectedReference == current.reference && ! expectedStamp == current.integer && ! ((newReference == current.reference && ! newStamp == current.integer) || ! atomicRef.weakCompareAndSet(current, ! new ReferenceIntegerPair<V>(newReference, ! newStamp))); } /** * Atomically sets the value of both the reference and stamp * to the given update values if the --- 124,135 ---- */ public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ! return compareAndSet(expectedReference, newReference, ! expectedStamp, newStamp); } /** * Atomically sets the value of both the reference and stamp * to the given update values if the
*** 147,164 **** */ public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ! ReferenceIntegerPair<V> current = atomicRef.get(); ! return expectedReference == current.reference && ! expectedStamp == current.integer && ((newReference == current.reference && ! newStamp == current.integer) || ! atomicRef.compareAndSet(current, ! new ReferenceIntegerPair<V>(newReference, ! newStamp))); } /** * Unconditionally sets the value of both the reference and stamp. --- 144,160 ---- */ public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ! Pair<V> current = pair; ! return ! expectedReference == current.reference && ! expectedStamp == current.stamp && ((newReference == current.reference && ! newStamp == current.stamp) || ! casPair(current, Pair.of(newReference, newStamp))); } /** * Unconditionally sets the value of both the reference and stamp.
*** 165,177 **** * * @param newReference the new value for the reference * @param newStamp the new value for the stamp */ public void set(V newReference, int newStamp) { ! ReferenceIntegerPair<V> current = atomicRef.get(); ! if (newReference != current.reference || newStamp != current.integer) ! atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); } /** * Atomically sets the value of the stamp to the given update value * if the current reference is {@code ==} to the expected --- 161,173 ---- * * @param newReference the new value for the reference * @param newStamp the new value for the stamp */ public void set(V newReference, int newStamp) { ! Pair<V> current = pair; ! if (newReference != current.reference || newStamp != current.stamp) ! this.pair = Pair.of(newReference, newStamp); } /** * Atomically sets the value of the stamp to the given update value * if the current reference is {@code ==} to the expected
*** 184,196 **** * @param expectedReference the expected value of the reference * @param newStamp the new value for the stamp * @return true if successful */ public boolean attemptStamp(V expectedReference, int newStamp) { ! ReferenceIntegerPair<V> current = atomicRef.get(); ! return expectedReference == current.reference && ! (newStamp == current.integer || ! atomicRef.compareAndSet(current, ! new ReferenceIntegerPair<V>(expectedReference, ! newStamp))); } } --- 180,213 ---- * @param expectedReference the expected value of the reference * @param newStamp the new value for the stamp * @return true if successful */ public boolean attemptStamp(V expectedReference, int newStamp) { ! Pair<V> current = pair; ! return ! expectedReference == current.reference && ! (newStamp == current.stamp || ! casPair(current, Pair.of(expectedReference, newStamp))); } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long pairOffset = + objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); + + private boolean casPair(Pair<V> cmp, Pair<V> val) { + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); + } + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } }