ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/atomic/AtomicStampedReference.java
Revision: 1.3
Committed: Sun Mar 16 03:31:26 2014 UTC (10 years, 3 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +1 -1 lines
Log Message:
typos

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