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

Print this page

        

@@ -36,58 +36,62 @@
 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
+ *
+ * <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 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 final AtomicReference<ReferenceBooleanPair<V>>  atomicRef;
+    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) {
-        atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark));
+        pair = Pair.of(initialRef, initialMark);
     }
 
     /**
      * Returns the current value of the reference.
      *
      * @return the current value of the reference
      */
     public V getReference() {
-        return atomicRef.get().reference;
+        return pair.reference;
     }
 
     /**
      * Returns the current value of the mark.
      *
      * @return the current value of the mark
      */
     public boolean isMarked() {
-        return atomicRef.get().bit;
+        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,13 +99,13 @@
      * @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;
+        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,17 +124,12 @@
      */
     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)));
+        return compareAndSet(expectedReference, newReference,
+                             expectedMark, newMark);
     }
 
     /**
      * Atomically sets the value of both the reference and mark
      * to the given update values if the

@@ -145,29 +144,29 @@
      */
     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)));
+        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) {
-        ReferenceBooleanPair<V> current = atomicRef.get();
-        if (newReference != current.reference || newMark != current.bit)
-            atomicRef.set(new ReferenceBooleanPair<V>(newReference, 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,13 +179,34 @@
      * @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)));
+        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;
+        }
+    }
 }