37 |
37 |
38 /** |
38 /** |
39 * An {@code AtomicStampedReference} maintains an object reference |
39 * An {@code AtomicStampedReference} maintains an object reference |
40 * along with an integer "stamp", that can be updated atomically. |
40 * along with an integer "stamp", that can be updated atomically. |
41 * |
41 * |
42 * <p> Implementation note. This implementation maintains stamped |
42 * <p>Implementation note: This implementation maintains stamped |
43 * references by creating internal objects representing "boxed" |
43 * references by creating internal objects representing "boxed" |
44 * [reference, integer] pairs. |
44 * [reference, integer] pairs. |
45 * |
45 * |
46 * @since 1.5 |
46 * @since 1.5 |
47 * @author Doug Lea |
47 * @author Doug Lea |
48 * @param <V> The type of object referred to by this reference |
48 * @param <V> The type of object referred to by this reference |
49 */ |
49 */ |
50 public class AtomicStampedReference<V> { |
50 public class AtomicStampedReference<V> { |
51 |
51 |
52 private static class ReferenceIntegerPair<T> { |
52 private static class Pair<T> { |
53 private final T reference; |
53 final T reference; |
54 private final int integer; |
54 final int stamp; |
55 ReferenceIntegerPair(T r, int i) { |
55 private Pair(T reference, int stamp) { |
56 reference = r; integer = i; |
56 this.reference = reference; |
|
57 this.stamp = stamp; |
57 } |
58 } |
58 } |
59 static <T> Pair<T> of(T reference, int stamp) { |
59 |
60 return new Pair<T>(reference, stamp); |
60 private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; |
61 } |
|
62 } |
|
63 |
|
64 private volatile Pair<V> pair; |
61 |
65 |
62 /** |
66 /** |
63 * Creates a new {@code AtomicStampedReference} with the given |
67 * Creates a new {@code AtomicStampedReference} with the given |
64 * initial values. |
68 * initial values. |
65 * |
69 * |
66 * @param initialRef the initial reference |
70 * @param initialRef the initial reference |
67 * @param initialStamp the initial stamp |
71 * @param initialStamp the initial stamp |
68 */ |
72 */ |
69 public AtomicStampedReference(V initialRef, int initialStamp) { |
73 public AtomicStampedReference(V initialRef, int initialStamp) { |
70 atomicRef = new AtomicReference<ReferenceIntegerPair<V>> |
74 pair = Pair.of(initialRef, initialStamp); |
71 (new ReferenceIntegerPair<V>(initialRef, initialStamp)); |
|
72 } |
75 } |
73 |
76 |
74 /** |
77 /** |
75 * Returns the current value of the reference. |
78 * Returns the current value of the reference. |
76 * |
79 * |
77 * @return the current value of the reference |
80 * @return the current value of the reference |
78 */ |
81 */ |
79 public V getReference() { |
82 public V getReference() { |
80 return atomicRef.get().reference; |
83 return pair.reference; |
81 } |
84 } |
82 |
85 |
83 /** |
86 /** |
84 * Returns the current value of the stamp. |
87 * Returns the current value of the stamp. |
85 * |
88 * |
86 * @return the current value of the stamp |
89 * @return the current value of the stamp |
87 */ |
90 */ |
88 public int getStamp() { |
91 public int getStamp() { |
89 return atomicRef.get().integer; |
92 return pair.stamp; |
90 } |
93 } |
91 |
94 |
92 /** |
95 /** |
93 * Returns the current values of both the reference and the stamp. |
96 * Returns the current values of both the reference and the stamp. |
94 * Typical usage is {@code int[1] holder; ref = v.get(holder); }. |
97 * Typical usage is {@code int[1] holder; ref = v.get(holder); }. |
96 * @param stampHolder an array of size of at least one. On return, |
99 * @param stampHolder an array of size of at least one. On return, |
97 * {@code stampholder[0]} will hold the value of the stamp. |
100 * {@code stampholder[0]} will hold the value of the stamp. |
98 * @return the current value of the reference |
101 * @return the current value of the reference |
99 */ |
102 */ |
100 public V get(int[] stampHolder) { |
103 public V get(int[] stampHolder) { |
101 ReferenceIntegerPair<V> p = atomicRef.get(); |
104 Pair<V> pair = this.pair; |
102 stampHolder[0] = p.integer; |
105 stampHolder[0] = pair.stamp; |
103 return p.reference; |
106 return pair.reference; |
104 } |
107 } |
105 |
108 |
106 /** |
109 /** |
107 * Atomically sets the value of both the reference and stamp |
110 * Atomically sets the value of both the reference and stamp |
108 * to the given update values if the |
111 * to the given update values if the |
117 * @param newReference the new value for the reference |
120 * @param newReference the new value for the reference |
118 * @param expectedStamp the expected value of the stamp |
121 * @param expectedStamp the expected value of the stamp |
119 * @param newStamp the new value for the stamp |
122 * @param newStamp the new value for the stamp |
120 * @return true if successful |
123 * @return true if successful |
121 */ |
124 */ |
122 public boolean weakCompareAndSet(V expectedReference, |
125 public boolean weakCompareAndSet(V expectedReference, |
123 V newReference, |
126 V newReference, |
124 int expectedStamp, |
127 int expectedStamp, |
125 int newStamp) { |
128 int newStamp) { |
126 ReferenceIntegerPair<V> current = atomicRef.get(); |
129 return compareAndSet(expectedReference, newReference, |
127 return expectedReference == current.reference && |
130 expectedStamp, newStamp); |
128 expectedStamp == current.integer && |
|
129 ((newReference == current.reference && |
|
130 newStamp == current.integer) || |
|
131 atomicRef.weakCompareAndSet(current, |
|
132 new ReferenceIntegerPair<V>(newReference, |
|
133 newStamp))); |
|
134 } |
131 } |
135 |
132 |
136 /** |
133 /** |
137 * Atomically sets the value of both the reference and stamp |
134 * Atomically sets the value of both the reference and stamp |
138 * to the given update values if the |
135 * to the given update values if the |
143 * @param newReference the new value for the reference |
140 * @param newReference the new value for the reference |
144 * @param expectedStamp the expected value of the stamp |
141 * @param expectedStamp the expected value of the stamp |
145 * @param newStamp the new value for the stamp |
142 * @param newStamp the new value for the stamp |
146 * @return true if successful |
143 * @return true if successful |
147 */ |
144 */ |
148 public boolean compareAndSet(V expectedReference, |
145 public boolean compareAndSet(V expectedReference, |
149 V newReference, |
146 V newReference, |
150 int expectedStamp, |
147 int expectedStamp, |
151 int newStamp) { |
148 int newStamp) { |
152 ReferenceIntegerPair<V> current = atomicRef.get(); |
149 Pair<V> current = pair; |
153 return expectedReference == current.reference && |
150 return |
154 expectedStamp == current.integer && |
151 expectedReference == current.reference && |
|
152 expectedStamp == current.stamp && |
155 ((newReference == current.reference && |
153 ((newReference == current.reference && |
156 newStamp == current.integer) || |
154 newStamp == current.stamp) || |
157 atomicRef.compareAndSet(current, |
155 casPair(current, Pair.of(newReference, newStamp))); |
158 new ReferenceIntegerPair<V>(newReference, |
|
159 newStamp))); |
|
160 } |
156 } |
161 |
157 |
162 |
158 |
163 /** |
159 /** |
164 * Unconditionally sets the value of both the reference and stamp. |
160 * Unconditionally sets the value of both the reference and stamp. |
165 * |
161 * |
166 * @param newReference the new value for the reference |
162 * @param newReference the new value for the reference |
167 * @param newStamp the new value for the stamp |
163 * @param newStamp the new value for the stamp |
168 */ |
164 */ |
169 public void set(V newReference, int newStamp) { |
165 public void set(V newReference, int newStamp) { |
170 ReferenceIntegerPair<V> current = atomicRef.get(); |
166 Pair<V> current = pair; |
171 if (newReference != current.reference || newStamp != current.integer) |
167 if (newReference != current.reference || newStamp != current.stamp) |
172 atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); |
168 this.pair = Pair.of(newReference, newStamp); |
173 } |
169 } |
174 |
170 |
175 /** |
171 /** |
176 * Atomically sets the value of the stamp to the given update value |
172 * Atomically sets the value of the stamp to the given update value |
177 * if the current reference is {@code ==} to the expected |
173 * if the current reference is {@code ==} to the expected |
184 * @param expectedReference the expected value of the reference |
180 * @param expectedReference the expected value of the reference |
185 * @param newStamp the new value for the stamp |
181 * @param newStamp the new value for the stamp |
186 * @return true if successful |
182 * @return true if successful |
187 */ |
183 */ |
188 public boolean attemptStamp(V expectedReference, int newStamp) { |
184 public boolean attemptStamp(V expectedReference, int newStamp) { |
189 ReferenceIntegerPair<V> current = atomicRef.get(); |
185 Pair<V> current = pair; |
190 return expectedReference == current.reference && |
186 return |
191 (newStamp == current.integer || |
187 expectedReference == current.reference && |
192 atomicRef.compareAndSet(current, |
188 (newStamp == current.stamp || |
193 new ReferenceIntegerPair<V>(expectedReference, |
189 casPair(current, Pair.of(expectedReference, newStamp))); |
194 newStamp))); |
190 } |
|
191 |
|
192 // Unsafe mechanics |
|
193 |
|
194 private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); |
|
195 private static final long pairOffset = |
|
196 objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class); |
|
197 |
|
198 private boolean casPair(Pair<V> cmp, Pair<V> val) { |
|
199 return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); |
|
200 } |
|
201 |
|
202 static long objectFieldOffset(sun.misc.Unsafe UNSAFE, |
|
203 String field, Class<?> klazz) { |
|
204 try { |
|
205 return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); |
|
206 } catch (NoSuchFieldException e) { |
|
207 // Convert Exception to corresponding Error |
|
208 NoSuchFieldError error = new NoSuchFieldError(field); |
|
209 error.initCause(e); |
|
210 throw error; |
|
211 } |
195 } |
212 } |
196 } |
213 } |