1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
/* * @(#)AtomicMarkableReference.java 1.7 06/06/15 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.concurrent.atomic; /** * An {@code AtomicMarkableReference} maintains an object reference * along with a mark bit, that can be updated atomically. * <p> * <p> Implementation note. This implementation maintains markable * references by creating internal objects representing "boxed" * [reference, boolean] pairs. * * @since 1.5 * @author Doug Lea * @param <V> The type of object referred to by this reference */ public class AtomicMarkableReference<V> { private static class ReferenceBooleanPair<T> { private final T reference; private final boolean bit; ReferenceBooleanPair(T r, boolean i) { reference = r; bit = i; } } private final AtomicReference<ReferenceBooleanPair<V>> atomicRef; /** * Creates a new {@code AtomicMarkableReference} with the given * initial values. * * @param initialRef the initial reference * @param initialMark the initial mark */ public AtomicMarkableReference(V initialRef, boolean initialMark) { atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark)); } /** * Returns the current value of the reference. * * @return the current value of the reference */ public V getReference() { return atomicRef.get().reference; } /** * Returns the current value of the mark. * * @return the current value of the mark */ public boolean isMarked() { return atomicRef.get().bit; } /** * Returns the current values of both the reference and the mark. * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }. * * @param markHolder an array of size of at least one. On return, * {@code markholder[0]} will hold the value of the mark. * @return the current value of the reference */ public V get(boolean[] markHolder) { ReferenceBooleanPair<V> p = atomicRef.get(); markHolder[0] = p.bit; return p.reference; } /** * Atomically sets the value of both the reference and mark * to the given update values if the * current reference is {@code ==} to the expected reference * and the current mark is equal to the expected mark. * * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * and does not provide ordering guarantees, so is only rarely an * appropriate alternative to {@code compareAndSet}. * * @param expectedReference the expected value of the reference * @param newReference the new value for the reference * @param expectedMark the expected value of the mark * @param newMark the new value for the mark * @return true if successful */ public boolean weakCompareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { ReferenceBooleanPair<V> current = atomicRef.get(); return expectedReference == current.reference && expectedMark == current.bit && ((newReference == current.reference && newMark == current.bit) || atomicRef.weakCompareAndSet(current, new ReferenceBooleanPair<V>(newReference, newMark))); } /** * Atomically sets the value of both the reference and mark * to the given update values if the * current reference is {@code ==} to the expected reference * and the current mark is equal to the expected mark. * * @param expectedReference the expected value of the reference * @param newReference the new value for the reference * @param expectedMark the expected value of the mark * @param newMark the new value for the mark * @return true if successful */ public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { ReferenceBooleanPair<V> current = atomicRef.get(); return expectedReference == current.reference && expectedMark == current.bit && ((newReference == current.reference && newMark == current.bit) || atomicRef.compareAndSet(current, new ReferenceBooleanPair<V>(newReference, newMark))); } /** * Unconditionally sets the value of both the reference and mark. * * @param newReference the new value for the reference * @param newMark the new value for the mark */ public void set(V newReference, boolean newMark) { ReferenceBooleanPair<V> current = atomicRef.get(); if (newReference != current.reference || newMark != current.bit) atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark)); } /** * Atomically sets the value of the mark to the given update value * if the current reference is {@code ==} to the expected * reference. Any given invocation of this operation may fail * (return {@code false}) spuriously, but repeated invocation * when the current value holds the expected value and no other * thread is also attempting to set the value will eventually * succeed. * * @param expectedReference the expected value of the reference * @param newMark the new value for the mark * @return true if successful */ public boolean attemptMark(V expectedReference, boolean newMark) { ReferenceBooleanPair<V> current = atomicRef.get(); return expectedReference == current.reference && (newMark == current.bit || atomicRef.compareAndSet (current, new ReferenceBooleanPair<V>(expectedReference, newMark))); } }