Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java
+++ new/src/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java
1 1 /*
2 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 3 *
4 4 * This code is free software; you can redistribute it and/or modify it
5 5 * under the terms of the GNU General Public License version 2 only, as
6 6 * published by the Free Software Foundation. Oracle designates this
7 7 * particular file as subject to the "Classpath" exception as provided
8 8 * by Oracle in the LICENSE file that accompanied this code.
9 9 *
10 10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 13 * version 2 for more details (a copy is included in the LICENSE file that
14 14 * accompanied this code).
15 15 *
16 16 * You should have received a copy of the GNU General Public License version
17 17 * 2 along with this work; if not, write to the Free Software Foundation,
18 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 19 *
20 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 21 * or visit www.oracle.com if you need additional information or have any
22 22 * questions.
23 23 */
24 24
25 25 /*
26 26 * This file is available under and governed by the GNU General Public
27 27 * License version 2 only, as published by the Free Software Foundation.
28 28 * However, the following notice accompanied the original version of this
29 29 * file:
30 30 *
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
31 31 * Written by Doug Lea with assistance from members of JCP JSR-166
32 32 * Expert Group and released to the public domain, as explained at
33 33 * http://creativecommons.org/licenses/publicdomain
34 34 */
35 35
36 36 package java.util.concurrent.atomic;
37 37
38 38 /**
39 39 * An {@code AtomicMarkableReference} maintains an object reference
40 40 * along with a mark bit, that can be updated atomically.
41 - * <p>
42 - * <p> Implementation note. This implementation maintains markable
41 + *
42 + * <p>Implementation note: This implementation maintains markable
43 43 * references by creating internal objects representing "boxed"
44 44 * [reference, boolean] pairs.
45 45 *
46 46 * @since 1.5
47 47 * @author Doug Lea
48 48 * @param <V> The type of object referred to by this reference
49 49 */
50 -public class AtomicMarkableReference<V> {
50 +public class AtomicMarkableReference<V> {
51 51
52 - private static class ReferenceBooleanPair<T> {
53 - private final T reference;
54 - private final boolean bit;
55 - ReferenceBooleanPair(T r, boolean i) {
56 - reference = r; bit = i;
52 + private static class Pair<T> {
53 + final T reference;
54 + final boolean mark;
55 + private Pair(T reference, boolean mark) {
56 + this.reference = reference;
57 + this.mark = mark;
57 58 }
59 + static <T> Pair<T> of(T reference, boolean mark) {
60 + return new Pair<T>(reference, mark);
61 + }
58 62 }
59 63
60 - private final AtomicReference<ReferenceBooleanPair<V>> atomicRef;
64 + private volatile Pair<V> pair;
61 65
62 66 /**
63 67 * Creates a new {@code AtomicMarkableReference} with the given
64 68 * initial values.
65 69 *
66 70 * @param initialRef the initial reference
67 71 * @param initialMark the initial mark
68 72 */
69 73 public AtomicMarkableReference(V initialRef, boolean initialMark) {
70 - atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark));
74 + pair = Pair.of(initialRef, initialMark);
71 75 }
72 76
73 77 /**
74 78 * Returns the current value of the reference.
75 79 *
76 80 * @return the current value of the reference
77 81 */
78 82 public V getReference() {
79 - return atomicRef.get().reference;
83 + return pair.reference;
80 84 }
81 85
82 86 /**
83 87 * Returns the current value of the mark.
84 88 *
85 89 * @return the current value of the mark
86 90 */
87 91 public boolean isMarked() {
88 - return atomicRef.get().bit;
92 + return pair.mark;
89 93 }
90 94
91 95 /**
92 96 * Returns the current values of both the reference and the mark.
93 97 * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
94 98 *
95 99 * @param markHolder an array of size of at least one. On return,
96 100 * {@code markholder[0]} will hold the value of the mark.
97 101 * @return the current value of the reference
98 102 */
99 103 public V get(boolean[] markHolder) {
100 - ReferenceBooleanPair<V> p = atomicRef.get();
101 - markHolder[0] = p.bit;
102 - return p.reference;
104 + Pair<V> pair = this.pair;
105 + markHolder[0] = pair.mark;
106 + return pair.reference;
103 107 }
104 108
105 109 /**
106 110 * Atomically sets the value of both the reference and mark
107 111 * to the given update values if the
108 112 * current reference is {@code ==} to the expected reference
109 113 * and the current mark is equal to the expected mark.
110 114 *
111 115 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
112 116 * and does not provide ordering guarantees, so is only rarely an
113 117 * appropriate alternative to {@code compareAndSet}.
114 118 *
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
115 119 * @param expectedReference the expected value of the reference
116 120 * @param newReference the new value for the reference
117 121 * @param expectedMark the expected value of the mark
118 122 * @param newMark the new value for the mark
119 123 * @return true if successful
120 124 */
121 125 public boolean weakCompareAndSet(V expectedReference,
122 126 V newReference,
123 127 boolean expectedMark,
124 128 boolean newMark) {
125 - ReferenceBooleanPair<V> current = atomicRef.get();
126 - return expectedReference == current.reference &&
127 - expectedMark == current.bit &&
128 - ((newReference == current.reference && newMark == current.bit) ||
129 - atomicRef.weakCompareAndSet(current,
130 - new ReferenceBooleanPair<V>(newReference,
131 - newMark)));
129 + return compareAndSet(expectedReference, newReference,
130 + expectedMark, newMark);
132 131 }
133 132
134 133 /**
135 134 * Atomically sets the value of both the reference and mark
136 135 * to the given update values if the
137 136 * current reference is {@code ==} to the expected reference
138 137 * and the current mark is equal to the expected mark.
139 138 *
140 139 * @param expectedReference the expected value of the reference
141 140 * @param newReference the new value for the reference
142 141 * @param expectedMark the expected value of the mark
143 142 * @param newMark the new value for the mark
144 143 * @return true if successful
145 144 */
146 145 public boolean compareAndSet(V expectedReference,
147 146 V newReference,
148 147 boolean expectedMark,
149 148 boolean newMark) {
150 - ReferenceBooleanPair<V> current = atomicRef.get();
151 - return expectedReference == current.reference &&
152 - expectedMark == current.bit &&
153 - ((newReference == current.reference && newMark == current.bit) ||
154 - atomicRef.compareAndSet(current,
155 - new ReferenceBooleanPair<V>(newReference,
156 - newMark)));
149 + Pair<V> current = pair;
150 + return
151 + expectedReference == current.reference &&
152 + expectedMark == current.mark &&
153 + ((newReference == current.reference &&
154 + newMark == current.mark) ||
155 + casPair(current, Pair.of(newReference, newMark)));
157 156 }
158 157
159 158 /**
160 159 * Unconditionally sets the value of both the reference and mark.
161 160 *
162 161 * @param newReference the new value for the reference
163 162 * @param newMark the new value for the mark
164 163 */
165 164 public void set(V newReference, boolean newMark) {
166 - ReferenceBooleanPair<V> current = atomicRef.get();
167 - if (newReference != current.reference || newMark != current.bit)
168 - atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark));
165 + Pair<V> current = pair;
166 + if (newReference != current.reference || newMark != current.mark)
167 + this.pair = Pair.of(newReference, newMark);
169 168 }
170 169
171 170 /**
172 171 * Atomically sets the value of the mark to the given update value
173 172 * if the current reference is {@code ==} to the expected
174 173 * reference. Any given invocation of this operation may fail
175 174 * (return {@code false}) spuriously, but repeated invocation
176 175 * when the current value holds the expected value and no other
177 176 * thread is also attempting to set the value will eventually
178 177 * succeed.
179 178 *
180 179 * @param expectedReference the expected value of the reference
181 180 * @param newMark the new value for the mark
182 181 * @return true if successful
183 182 */
184 183 public boolean attemptMark(V expectedReference, boolean newMark) {
185 - ReferenceBooleanPair<V> current = atomicRef.get();
186 - return expectedReference == current.reference &&
187 - (newMark == current.bit ||
188 - atomicRef.compareAndSet
189 - (current, new ReferenceBooleanPair<V>(expectedReference,
190 - newMark)));
184 + Pair<V> current = pair;
185 + return
186 + expectedReference == current.reference &&
187 + (newMark == current.mark ||
188 + casPair(current, Pair.of(expectedReference, newMark)));
191 189 }
190 +
191 + // Unsafe mechanics
192 +
193 + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
194 + private static final long pairOffset =
195 + objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
196 +
197 + private boolean casPair(Pair<V> cmp, Pair<V> val) {
198 + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
199 + }
200 +
201 + static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
202 + String field, Class<?> klazz) {
203 + try {
204 + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
205 + } catch (NoSuchFieldException e) {
206 + // Convert Exception to corresponding Error
207 + NoSuchFieldError error = new NoSuchFieldError(field);
208 + error.initCause(e);
209 + throw error;
210 + }
211 + }
192 212 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX