AtomicStampedReference.java revision 8eb35c835be1345d3873a82cc9e42f944d698afd
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Written by Doug Lea with assistance from members of JCP JSR-166 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Expert Group and released to the public domain, as explained at 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://creativecommons.org/licenses/publicdomain 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.concurrent.atomic; 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 10bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * An {@code AtomicStampedReference} maintains an object reference 11bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * along with an integer "stamp", that can be updated atomically. 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 138eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson * <p>Implementation note: This implementation maintains stamped 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * references by creating internal objects representing "boxed" 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * [reference, integer] pairs. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @since 1.5 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @author Doug Lea 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param <V> The type of object referred to by this reference 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 218eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilsonpublic class AtomicStampedReference<V> { 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 238eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private static class Pair<T> { 248eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson final T reference; 258eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson final int stamp; 268eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private Pair(T reference, int stamp) { 278eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson this.reference = reference; 288eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson this.stamp = stamp; 298eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson } 308eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson static <T> Pair<T> of(T reference, int stamp) { 318eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return new Pair<T>(reference, stamp); 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 358eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private volatile Pair<V> pair; 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 38bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * Creates a new {@code AtomicStampedReference} with the given 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * initial values. 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param initialRef the initial reference 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param initialStamp the initial stamp 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public AtomicStampedReference(V initialRef, int initialStamp) { 458eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson pair = Pair.of(initialRef, initialStamp); 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the current value of the reference. 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the current value of the reference 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public V getReference() { 548eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return pair.reference; 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the current value of the stamp. 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the current value of the stamp 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int getStamp() { 638eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return pair.stamp; 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the current values of both the reference and the stamp. 68bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * Typical usage is {@code int[1] holder; ref = v.get(holder); }. 69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param stampHolder an array of size of at least one. On return, 71bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * {@code stampholder[0]} will hold the value of the stamp. 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the current value of the reference 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public V get(int[] stampHolder) { 758eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson Pair<V> pair = this.pair; 768eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson stampHolder[0] = pair.stamp; 778eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return pair.reference; 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Atomically sets the value of both the reference and stamp 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * to the given update values if the 83bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * current reference is {@code ==} to the expected reference 84bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * and the current stamp is equal to the expected stamp. 85bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * 86bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 87bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * and does not provide ordering guarantees, so is only rarely an 88bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * appropriate alternative to {@code compareAndSet}. 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param expectedReference the expected value of the reference 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newReference the new value for the reference 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param expectedStamp the expected value of the stamp 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newStamp the new value for the stamp 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return true if successful 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 968eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson public boolean weakCompareAndSet(V expectedReference, 978eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson V newReference, 988eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson int expectedStamp, 998eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson int newStamp) { 1008eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return compareAndSet(expectedReference, newReference, 1018eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson expectedStamp, newStamp); 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Atomically sets the value of both the reference and stamp 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * to the given update values if the 107bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * current reference is {@code ==} to the expected reference 108bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * and the current stamp is equal to the expected stamp. 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param expectedReference the expected value of the reference 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newReference the new value for the reference 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param expectedStamp the expected value of the stamp 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newStamp the new value for the stamp 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return true if successful 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1168eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson public boolean compareAndSet(V expectedReference, 1178eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson V newReference, 1188eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson int expectedStamp, 1198eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson int newStamp) { 1208eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson Pair<V> current = pair; 1218eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return 1228eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson expectedReference == current.reference && 1238eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson expectedStamp == current.stamp && 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ((newReference == current.reference && 1258eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson newStamp == current.stamp) || 1268eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson casPair(current, Pair.of(newReference, newStamp))); 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unconditionally sets the value of both the reference and stamp. 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newReference the new value for the reference 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newStamp the new value for the stamp 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void set(V newReference, int newStamp) { 1378eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson Pair<V> current = pair; 1388eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson if (newReference != current.reference || newStamp != current.stamp) 1398eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson this.pair = Pair.of(newReference, newStamp); 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Atomically sets the value of the stamp to the given update value 144bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * if the current reference is {@code ==} to the expected 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * reference. Any given invocation of this operation may fail 146bba8d1acd6dfff06c94d761c67a30154ca5ca5dfJesse Wilson * (return {@code false}) spuriously, but repeated invocation 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * when the current value holds the expected value and no other 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * thread is also attempting to set the value will eventually 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * succeed. 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param expectedReference the expected value of the reference 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param newStamp the new value for the stamp 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return true if successful 154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public boolean attemptStamp(V expectedReference, int newStamp) { 1568eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson Pair<V> current = pair; 1578eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return 1588eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson expectedReference == current.reference && 1598eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson (newStamp == current.stamp || 1608eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson casPair(current, Pair.of(expectedReference, newStamp))); 1618eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson } 1628eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson 1638eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson // Unsafe mechanics 1648eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson 1658eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.THE_ONE; // android-changed 1668eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private static final long pairOffset = 1678eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); 1688eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson 1698eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson private boolean casPair(Pair<V> cmp, Pair<V> val) { 1708eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); 1718eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson } 1728eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson 1738eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson static long objectFieldOffset(sun.misc.Unsafe UNSAFE, 1748eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson String field, Class<?> klazz) { 1758eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson try { 1768eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); 1778eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson } catch (NoSuchFieldException e) { 1788eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson // Convert Exception to corresponding Error 1798eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson NoSuchFieldError error = new NoSuchFieldError(field); 1808eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson error.initCause(e); 1818eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson throw error; 1828eb35c835be1345d3873a82cc9e42f944d698afdJesse Wilson } 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 185