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