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>AtomicMarkableReference</tt> maintains an object reference
011: * along with a mark bit, that can be updated atomically.
012: * <p>
013: * <p> Implementation note. This implementation maintains markable
014: * references by creating internal objects representing "boxed"
015: * [reference, boolean] 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 AtomicMarkableReference<V> {
022:
023: private static class ReferenceBooleanPair<T> {
024: private final T reference;
025: private final boolean bit;
026:
027: ReferenceBooleanPair(T r, boolean i) {
028: reference = r;
029: bit = i;
030: }
031: }
032:
033: private final AtomicReference<ReferenceBooleanPair<V>> atomicRef;
034:
035: /**
036: * Creates a new <tt>AtomicMarkableReference</tt> with the given
037: * initial values.
038: *
039: * @param initialRef the initial reference
040: * @param initialMark the initial mark
041: */
042: public AtomicMarkableReference(V initialRef, boolean initialMark) {
043: atomicRef = new AtomicReference<ReferenceBooleanPair<V>>(
044: new ReferenceBooleanPair<V>(initialRef, initialMark));
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 mark.
058: *
059: * @return the current value of the mark
060: */
061: public boolean isMarked() {
062: return atomicRef.get().bit;
063: }
064:
065: /**
066: * Returns the current values of both the reference and the mark.
067: * Typical usage is <tt>boolean[1] holder; ref = v.get(holder); </tt>.
068: *
069: * @param markHolder an array of size of at least one. On return,
070: * <tt>markholder[0]</tt> will hold the value of the mark.
071: * @return the current value of the reference
072: */
073: public V get(boolean[] markHolder) {
074: ReferenceBooleanPair<V> p = atomicRef.get();
075: markHolder[0] = p.bit;
076: return p.reference;
077: }
078:
079: /**
080: * Atomically sets the value of both the reference and mark
081: * to the given update values if the
082: * current reference is <tt>==</tt> to the expected reference
083: * and the current mark is equal to the expected mark. 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 expectedMark the expected value of the mark
092: * @param newMark the new value for the mark
093: * @return true if successful
094: */
095: public boolean weakCompareAndSet(V expectedReference,
096: V newReference, boolean expectedMark, boolean newMark) {
097: ReferenceBooleanPair current = atomicRef.get();
098: return expectedReference == current.reference
099: && expectedMark == current.bit
100: && ((newReference == current.reference && newMark == current.bit) || atomicRef
101: .weakCompareAndSet(current,
102: new ReferenceBooleanPair<V>(
103: newReference, newMark)));
104: }
105:
106: /**
107: * Atomically sets the value of both the reference and mark
108: * to the given update values if the
109: * current reference is <tt>==</tt> to the expected reference
110: * and the current mark is equal to the expected mark.
111: *
112: * @param expectedReference the expected value of the reference
113: * @param newReference the new value for the reference
114: * @param expectedMark the expected value of the mark
115: * @param newMark the new value for the mark
116: * @return true if successful
117: */
118: public boolean compareAndSet(V expectedReference, V newReference,
119: boolean expectedMark, boolean newMark) {
120: ReferenceBooleanPair current = atomicRef.get();
121: return expectedReference == current.reference
122: && expectedMark == current.bit
123: && ((newReference == current.reference && newMark == current.bit) || atomicRef
124: .compareAndSet(current,
125: new ReferenceBooleanPair<V>(
126: newReference, newMark)));
127: }
128:
129: /**
130: * Unconditionally sets the value of both the reference and mark.
131: *
132: * @param newReference the new value for the reference
133: * @param newMark the new value for the mark
134: */
135: public void set(V newReference, boolean newMark) {
136: ReferenceBooleanPair current = atomicRef.get();
137: if (newReference != current.reference || newMark != current.bit)
138: atomicRef.set(new ReferenceBooleanPair<V>(newReference,
139: newMark));
140: }
141:
142: /**
143: * Atomically sets the value of the mark to the given update value
144: * if the current reference is <tt>==</tt> to the expected
145: * reference. Any given invocation of this operation may fail
146: * (return <tt>false</tt>) 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 newMark the new value for the mark
153: * @return true if successful
154: */
155: public boolean attemptMark(V expectedReference, boolean newMark) {
156: ReferenceBooleanPair current = atomicRef.get();
157: return expectedReference == current.reference
158: && (newMark == current.bit || atomicRef.compareAndSet(
159: current, new ReferenceBooleanPair<V>(
160: expectedReference, newMark)));
161: }
162: }
|