ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/atomic/AtomicStampedReference.java
Revision: 1.26
Committed: Sat Oct 13 18:52:09 2018 UTC (5 years, 7 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.25: +6 -8 lines
Log Message:
Avoid broken javadoc links

File Contents

# Content
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/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent.atomic;
8
9 import java.lang.invoke.MethodHandles;
10 import java.lang.invoke.VarHandle;
11
12 /**
13 * An {@code AtomicStampedReference} maintains an object reference
14 * along with an integer "stamp", that can be updated atomically.
15 *
16 * <p>Implementation note: This implementation maintains stamped
17 * references by creating internal objects representing "boxed"
18 * [reference, integer] pairs.
19 *
20 * @since 1.5
21 * @author Doug Lea
22 * @param <V> The type of object referred to by this reference
23 */
24 public class AtomicStampedReference<V> {
25
26 private static class Pair<T> {
27 final T reference;
28 final int stamp;
29 private Pair(T reference, int stamp) {
30 this.reference = reference;
31 this.stamp = stamp;
32 }
33 static <T> Pair<T> of(T reference, int stamp) {
34 return new Pair<T>(reference, stamp);
35 }
36 }
37
38 private volatile Pair<V> pair;
39
40 /**
41 * Creates a new {@code AtomicStampedReference} with the given
42 * initial values.
43 *
44 * @param initialRef the initial reference
45 * @param initialStamp the initial stamp
46 */
47 public AtomicStampedReference(V initialRef, int initialStamp) {
48 pair = Pair.of(initialRef, initialStamp);
49 }
50
51 /**
52 * Returns the current value of the reference.
53 *
54 * @return the current value of the reference
55 */
56 public V getReference() {
57 return pair.reference;
58 }
59
60 /**
61 * Returns the current value of the stamp.
62 *
63 * @return the current value of the stamp
64 */
65 public int getStamp() {
66 return pair.stamp;
67 }
68
69 /**
70 * Returns the current values of both the reference and the stamp.
71 * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
72 *
73 * @param stampHolder an array of size of at least one. On return,
74 * {@code stampHolder[0]} will hold the value of the stamp.
75 * @return the current value of the reference
76 */
77 public V get(int[] stampHolder) {
78 Pair<V> pair = this.pair;
79 stampHolder[0] = pair.stamp;
80 return pair.reference;
81 }
82
83 /**
84 * Atomically sets the value of both the reference and stamp to
85 * the given update values if the current reference is {@code ==}
86 * to the expected reference and the current stamp is equal to the
87 * expected stamp. This operation may fail spuriously and does not
88 * provide ordering guarantees, so is only rarely an
89 * appropriate alternative to {@code compareAndSet}.
90 *
91 * @param expectedReference the expected value of the reference
92 * @param newReference the new value for the reference
93 * @param expectedStamp the expected value of the stamp
94 * @param newStamp the new value for the stamp
95 * @return {@code true} if successful
96 */
97 public boolean weakCompareAndSet(V expectedReference,
98 V newReference,
99 int expectedStamp,
100 int newStamp) {
101 return compareAndSet(expectedReference, newReference,
102 expectedStamp, newStamp);
103 }
104
105 /**
106 * Atomically sets the value of both the reference and stamp
107 * to the given update values if the
108 * current reference is {@code ==} to the expected reference
109 * and the current stamp is equal to the expected stamp.
110 *
111 * @param expectedReference the expected value of the reference
112 * @param newReference the new value for the reference
113 * @param expectedStamp the expected value of the stamp
114 * @param newStamp the new value for the stamp
115 * @return {@code true} if successful
116 */
117 public boolean compareAndSet(V expectedReference,
118 V newReference,
119 int expectedStamp,
120 int newStamp) {
121 Pair<V> current = pair;
122 return
123 expectedReference == current.reference &&
124 expectedStamp == current.stamp &&
125 ((newReference == current.reference &&
126 newStamp == current.stamp) ||
127 casPair(current, Pair.of(newReference, newStamp)));
128 }
129
130 /**
131 * Unconditionally sets the value of both the reference and stamp.
132 *
133 * @param newReference the new value for the reference
134 * @param newStamp the new value for the stamp
135 */
136 public void set(V newReference, int newStamp) {
137 Pair<V> current = pair;
138 if (newReference != current.reference || newStamp != current.stamp)
139 this.pair = Pair.of(newReference, newStamp);
140 }
141
142 /**
143 * Atomically sets the value of the stamp to the given update value
144 * if the current reference is {@code ==} to the expected
145 * reference. Any given invocation of this operation may fail
146 * (return {@code false}) spuriously, but repeated invocation
147 * when the current value holds the expected value and no other
148 * thread is also attempting to set the value will eventually
149 * succeed.
150 *
151 * @param expectedReference the expected value of the reference
152 * @param newStamp the new value for the stamp
153 * @return {@code true} if successful
154 */
155 public boolean attemptStamp(V expectedReference, int newStamp) {
156 Pair<V> current = pair;
157 return
158 expectedReference == current.reference &&
159 (newStamp == current.stamp ||
160 casPair(current, Pair.of(expectedReference, newStamp)));
161 }
162
163 // VarHandle mechanics
164 private static final VarHandle PAIR;
165 static {
166 try {
167 MethodHandles.Lookup l = MethodHandles.lookup();
168 PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
169 Pair.class);
170 } catch (ReflectiveOperationException e) {
171 throw new ExceptionInInitializerError(e);
172 }
173 }
174
175 private boolean casPair(Pair<V> cmp, Pair<V> val) {
176 return PAIR.compareAndSet(this, cmp, val);
177 }
178 }