AtomicMarkableReference.java revision 8eb35c835be1345d3873a82cc9e42f944d698afd
1/*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/licenses/publicdomain
5 */
6
7package java.util.concurrent.atomic;
8
9import sun.misc.Unsafe;
10
11/**
12 * An {@code AtomicMarkableReference} maintains an object reference
13 * along with a mark bit, that can be updated atomically.
14 *
15 * <p>Implementation note: This implementation maintains markable
16 * references by creating internal objects representing "boxed"
17 * [reference, boolean] pairs.
18 *
19 * @since 1.5
20 * @author Doug Lea
21 * @param <V> The type of object referred to by this reference
22 */
23public class AtomicMarkableReference<V> {
24
25    private static class Pair<T> {
26        final T reference;
27        final boolean mark;
28        private Pair(T reference, boolean mark) {
29            this.reference = reference;
30            this.mark = mark;
31        }
32        static <T> Pair<T> of(T reference, boolean mark) {
33            return new Pair<T>(reference, mark);
34        }
35    }
36
37    private volatile Pair<V> pair;
38
39    /**
40     * Creates a new {@code AtomicMarkableReference} with the given
41     * initial values.
42     *
43     * @param initialRef the initial reference
44     * @param initialMark the initial mark
45     */
46    public AtomicMarkableReference(V initialRef, boolean initialMark) {
47        pair = Pair.of(initialRef, initialMark);
48    }
49
50    /**
51     * Returns the current value of the reference.
52     *
53     * @return the current value of the reference
54     */
55    public V getReference() {
56        return pair.reference;
57    }
58
59    /**
60     * Returns the current value of the mark.
61     *
62     * @return the current value of the mark
63     */
64    public boolean isMarked() {
65        return pair.mark;
66    }
67
68    /**
69     * Returns the current values of both the reference and the mark.
70     * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
71     *
72     * @param markHolder an array of size of at least one. On return,
73     * {@code markholder[0]} will hold the value of the mark.
74     * @return the current value of the reference
75     */
76    public V get(boolean[] markHolder) {
77        Pair<V> pair = this.pair;
78        markHolder[0] = pair.mark;
79        return pair.reference;
80    }
81
82    /**
83     * Atomically sets the value of both the reference and mark
84     * to the given update values if the
85     * current reference is {@code ==} to the expected reference
86     * and the current mark is equal to the expected mark.
87     *
88     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
89     * and does not provide ordering guarantees, so is only rarely an
90     * appropriate alternative to {@code compareAndSet}.
91     *
92     * @param expectedReference the expected value of the reference
93     * @param newReference the new value for the reference
94     * @param expectedMark the expected value of the mark
95     * @param newMark the new value for the mark
96     * @return true if successful
97     */
98    public boolean weakCompareAndSet(V       expectedReference,
99                                     V       newReference,
100                                     boolean expectedMark,
101                                     boolean newMark) {
102        return compareAndSet(expectedReference, newReference,
103                             expectedMark, newMark);
104    }
105
106    /**
107     * Atomically sets the value of both the reference and mark
108     * to the given update values if the
109     * current reference is {@code ==} to the expected reference
110     * and the current mark is equal to the expected mark.
111     *
112     * @param expectedReference the expected value of the reference
113     * @param newReference the new value for the reference
114     * @param expectedMark the expected value of the mark
115     * @param newMark the new value for the mark
116     * @return true if successful
117     */
118    public boolean compareAndSet(V       expectedReference,
119                                 V       newReference,
120                                 boolean expectedMark,
121                                 boolean newMark) {
122        Pair<V> current = pair;
123        return
124            expectedReference == current.reference &&
125            expectedMark == current.mark &&
126            ((newReference == current.reference &&
127              newMark == current.mark) ||
128             casPair(current, Pair.of(newReference, newMark)));
129    }
130
131    /**
132     * Unconditionally sets the value of both the reference and mark.
133     *
134     * @param newReference the new value for the reference
135     * @param newMark the new value for the mark
136     */
137    public void set(V newReference, boolean newMark) {
138        Pair<V> current = pair;
139        if (newReference != current.reference || newMark != current.mark)
140            this.pair = Pair.of(newReference, newMark);
141    }
142
143    /**
144     * Atomically sets the value of the mark to the given update value
145     * if the current reference is {@code ==} to the expected
146     * reference.  Any given invocation of this operation may fail
147     * (return {@code false}) spuriously, but repeated invocation
148     * when the current value holds the expected value and no other
149     * thread is also attempting to set the value will eventually
150     * succeed.
151     *
152     * @param expectedReference the expected value of the reference
153     * @param newMark the new value for the mark
154     * @return true if successful
155     */
156    public boolean attemptMark(V expectedReference, boolean newMark) {
157        Pair<V> current = pair;
158        return
159            expectedReference == current.reference &&
160            (newMark == current.mark ||
161             casPair(current, Pair.of(expectedReference, newMark)));
162    }
163
164    // Unsafe mechanics
165
166    private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.THE_ONE; // android-changed
167    private static final long pairOffset =
168        objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
169
170    private boolean casPair(Pair<V> cmp, Pair<V> val) {
171        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
172    }
173
174    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
175                                  String field, Class<?> klazz) {
176        try {
177            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
178        } catch (NoSuchFieldException e) {
179            // Convert Exception to corresponding Error
180            NoSuchFieldError error = new NoSuchFieldError(field);
181            error.initCause(e);
182            throw error;
183        }
184    }
185}
186