src/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java

Print this page

        

*** 36,93 **** 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); }. --- 36,97 ---- package java.util.concurrent.atomic; /** * An {@code AtomicMarkableReference} maintains an object reference * along with a mark bit, that can be updated atomically. ! * ! * <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 Pair<T> { ! final T reference; ! final boolean mark; ! private Pair(T reference, boolean mark) { ! this.reference = reference; ! this.mark = mark; } + static <T> Pair<T> of(T reference, boolean mark) { + return new Pair<T>(reference, mark); } + } ! private volatile Pair<V> pair; /** * 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) { ! pair = Pair.of(initialRef, initialMark); } /** * Returns the current value of the reference. * * @return the current value of the reference */ public V getReference() { ! return pair.reference; } /** * Returns the current value of the mark. * * @return the current value of the mark */ public boolean isMarked() { ! return pair.mark; } /** * Returns the current values of both the reference and the mark. * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
*** 95,107 **** * @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 --- 99,111 ---- * @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) { ! Pair<V> pair = this.pair; ! markHolder[0] = pair.mark; ! return pair.reference; } /** * Atomically sets the value of both the reference and mark * to the given update values if the
*** 120,136 **** */ 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 --- 124,135 ---- */ public boolean weakCompareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { ! return compareAndSet(expectedReference, newReference, ! expectedMark, newMark); } /** * Atomically sets the value of both the reference and mark * to the given update values if the
*** 145,173 **** */ 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 --- 144,172 ---- */ public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { ! Pair<V> current = pair; ! return ! expectedReference == current.reference && ! expectedMark == current.mark && ! ((newReference == current.reference && ! newMark == current.mark) || ! casPair(current, Pair.of(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) { ! Pair<V> current = pair; ! if (newReference != current.reference || newMark != current.mark) ! this.pair = Pair.of(newReference, newMark); } /** * Atomically sets the value of the mark to the given update value * if the current reference is {@code ==} to the expected
*** 180,192 **** * @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))); } } --- 179,212 ---- * @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) { ! Pair<V> current = pair; ! return ! expectedReference == current.reference && ! (newMark == current.mark || ! casPair(current, Pair.of(expectedReference, newMark))); } + + // Unsafe mechanics + + private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe(); + private static final long pairOffset = + objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class); + + private boolean casPair(Pair<V> cmp, Pair<V> val) { + return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); + } + + static long objectFieldOffset(sun.misc.Unsafe UNSAFE, + String field, Class<?> klazz) { + try { + return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); + } catch (NoSuchFieldException e) { + // Convert Exception to corresponding Error + NoSuchFieldError error = new NoSuchFieldError(field); + error.initCause(e); + throw error; + } + } }