001: /*
002: * Written by Doug Lea with assistance from members of JCP JSR-166
003: * Expert Group and released to the public domain, as explained at
004: * http://creativecommons.org/licenses/publicdomain
005: */
006:
007: package java.util.concurrent.atomic;
008:
009: /**
010: * An <tt>AtomicStampedReference</tt> maintains an object reference
011: * along with an integer "stamp", that can be updated atomically.
012: *
013: * <p> Implementation note. This implementation maintains stamped
014: * references by creating internal objects representing "boxed"
015: * [reference, integer] pairs.
016: *
017: * @since 1.5
018: * @author Doug Lea
019: * @param <V> The type of object referred to by this reference
020: */
021: public class AtomicStampedReference<V> {
022:
023: private static class ReferenceIntegerPair<T> {
024: private final T reference;
025: private final int integer;
026:
027: ReferenceIntegerPair(T r, int i) {
028: reference = r;
029: integer = i;
030: }
031: }
032:
033: private final AtomicReference<ReferenceIntegerPair<V>> atomicRef;
034:
035: /**
036: * Creates a new <tt>AtomicStampedReference</tt> with the given
037: * initial values.
038: *
039: * @param initialRef the initial reference
040: * @param initialStamp the initial stamp
041: */
042: public AtomicStampedReference(V initialRef, int initialStamp) {
043: atomicRef = new AtomicReference<ReferenceIntegerPair<V>>(
044: new ReferenceIntegerPair<V>(initialRef, initialStamp));
045: }
046:
047: /**
048: * Returns the current value of the reference.
049: *
050: * @return the current value of the reference
051: */
052: public V getReference() {
053: return atomicRef.get().reference;
054: }
055:
056: /**
057: * Returns the current value of the stamp.
058: *
059: * @return the current value of the stamp
060: */
061: public int getStamp() {
062: return atomicRef.get().integer;
063: }
064:
065: /**
066: * Returns the current values of both the reference and the stamp.
067: * Typical usage is <tt>int[1] holder; ref = v.get(holder); </tt>.
068: *
069: * @param stampHolder an array of size of at least one. On return,
070: * <tt>stampholder[0]</tt> will hold the value of the stamp.
071: * @return the current value of the reference
072: */
073: public V get(int[] stampHolder) {
074: ReferenceIntegerPair<V> p = atomicRef.get();
075: stampHolder[0] = p.integer;
076: return p.reference;
077: }
078:
079: /**
080: * Atomically sets the value of both the reference and stamp
081: * to the given update values if the
082: * current reference is <tt>==</tt> to the expected reference
083: * and the current stamp is equal to the expected stamp. Any given
084: * invocation of this operation may fail (return
085: * <tt>false</tt>) spuriously, but repeated invocation when
086: * the current value holds the expected value and no other thread
087: * is also attempting to set the value will eventually succeed.
088: *
089: * @param expectedReference the expected value of the reference
090: * @param newReference the new value for the reference
091: * @param expectedStamp the expected value of the stamp
092: * @param newStamp the new value for the stamp
093: * @return true if successful
094: */
095: public boolean weakCompareAndSet(V expectedReference,
096: V newReference, int expectedStamp, int newStamp) {
097: ReferenceIntegerPair current = atomicRef.get();
098: return expectedReference == current.reference
099: && expectedStamp == current.integer
100: && ((newReference == current.reference && newStamp == current.integer) || atomicRef
101: .weakCompareAndSet(current,
102: new ReferenceIntegerPair<V>(
103: newReference, newStamp)));
104: }
105:
106: /**
107: * Atomically sets the value of both the reference and stamp
108: * to the given update values if the
109: * current reference is <tt>==</tt> to the expected reference
110: * and the current stamp is equal to the expected stamp.
111: *
112: * @param expectedReference the expected value of the reference
113: * @param newReference the new value for the reference
114: * @param expectedStamp the expected value of the stamp
115: * @param newStamp the new value for the stamp
116: * @return true if successful
117: */
118: public boolean compareAndSet(V expectedReference, V newReference,
119: int expectedStamp, int newStamp) {
120: ReferenceIntegerPair current = atomicRef.get();
121: return expectedReference == current.reference
122: && expectedStamp == current.integer
123: && ((newReference == current.reference && newStamp == current.integer) || atomicRef
124: .compareAndSet(current,
125: new ReferenceIntegerPair<V>(
126: 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: ReferenceIntegerPair current = atomicRef.get();
137: if (newReference != current.reference
138: || newStamp != current.integer)
139: atomicRef.set(new ReferenceIntegerPair<V>(newReference,
140: newStamp));
141: }
142:
143: /**
144: * Atomically sets the value of the stamp to the given update value
145: * if the current reference is <tt>==</tt> to the expected
146: * reference. Any given invocation of this operation may fail
147: * (return <tt>false</tt>) 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 newStamp the new value for the stamp
154: * @return true if successful
155: */
156: public boolean attemptStamp(V expectedReference, int newStamp) {
157: ReferenceIntegerPair current = atomicRef.get();
158: return expectedReference == current.reference
159: && (newStamp == current.integer || atomicRef
160: .compareAndSet(current,
161: new ReferenceIntegerPair<V>(
162: expectedReference, newStamp)));
163: }
164: }
|