Print this page


Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java
          +++ new/src/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java
↓ open down ↓ 30 lines elided ↑ open up ↑
  31   31   * Written by Doug Lea with assistance from members of JCP JSR-166
  32   32   * Expert Group and released to the public domain, as explained at
  33   33   * http://creativecommons.org/licenses/publicdomain
  34   34   */
  35   35  
  36   36  package java.util.concurrent.atomic;
  37   37  
  38   38  /**
  39   39   * An {@code AtomicMarkableReference} maintains an object reference
  40   40   * along with a mark bit, that can be updated atomically.
  41      - * <p>
  42      - * <p> Implementation note. This implementation maintains markable
       41 + *
       42 + * <p>Implementation note: This implementation maintains markable
  43   43   * references by creating internal objects representing "boxed"
  44   44   * [reference, boolean] pairs.
  45   45   *
  46   46   * @since 1.5
  47   47   * @author Doug Lea
  48   48   * @param <V> The type of object referred to by this reference
  49   49   */
  50      -public class AtomicMarkableReference<V>  {
       50 +public class AtomicMarkableReference<V> {
  51   51  
  52      -    private static class ReferenceBooleanPair<T> {
  53      -        private final T reference;
  54      -        private final boolean bit;
  55      -        ReferenceBooleanPair(T r, boolean i) {
  56      -            reference = r; bit = i;
       52 +    private static class Pair<T> {
       53 +        final T reference;
       54 +        final boolean mark;
       55 +        private Pair(T reference, boolean mark) {
       56 +            this.reference = reference;
       57 +            this.mark = mark;
  57   58          }
       59 +        static <T> Pair<T> of(T reference, boolean mark) {
       60 +            return new Pair<T>(reference, mark);
       61 +        }
  58   62      }
  59   63  
  60      -    private final AtomicReference<ReferenceBooleanPair<V>>  atomicRef;
       64 +    private volatile Pair<V> pair;
  61   65  
  62   66      /**
  63   67       * Creates a new {@code AtomicMarkableReference} with the given
  64   68       * initial values.
  65   69       *
  66   70       * @param initialRef the initial reference
  67   71       * @param initialMark the initial mark
  68   72       */
  69   73      public AtomicMarkableReference(V initialRef, boolean initialMark) {
  70      -        atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark));
       74 +        pair = Pair.of(initialRef, initialMark);
  71   75      }
  72   76  
  73   77      /**
  74   78       * Returns the current value of the reference.
  75   79       *
  76   80       * @return the current value of the reference
  77   81       */
  78   82      public V getReference() {
  79      -        return atomicRef.get().reference;
       83 +        return pair.reference;
  80   84      }
  81   85  
  82   86      /**
  83   87       * Returns the current value of the mark.
  84   88       *
  85   89       * @return the current value of the mark
  86   90       */
  87   91      public boolean isMarked() {
  88      -        return atomicRef.get().bit;
       92 +        return pair.mark;
  89   93      }
  90   94  
  91   95      /**
  92   96       * Returns the current values of both the reference and the mark.
  93   97       * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
  94   98       *
  95   99       * @param markHolder an array of size of at least one. On return,
  96  100       * {@code markholder[0]} will hold the value of the mark.
  97  101       * @return the current value of the reference
  98  102       */
  99  103      public V get(boolean[] markHolder) {
 100      -        ReferenceBooleanPair<V> p = atomicRef.get();
 101      -        markHolder[0] = p.bit;
 102      -        return p.reference;
      104 +        Pair<V> pair = this.pair;
      105 +        markHolder[0] = pair.mark;
      106 +        return pair.reference;
 103  107      }
 104  108  
 105  109      /**
 106  110       * Atomically sets the value of both the reference and mark
 107  111       * to the given update values if the
 108  112       * current reference is {@code ==} to the expected reference
 109  113       * and the current mark is equal to the expected mark.
 110  114       *
 111  115       * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
 112  116       * and does not provide ordering guarantees, so is only rarely an
↓ open down ↓ 2 lines elided ↑ open up ↑
 115  119       * @param expectedReference the expected value of the reference
 116  120       * @param newReference the new value for the reference
 117  121       * @param expectedMark the expected value of the mark
 118  122       * @param newMark the new value for the mark
 119  123       * @return true if successful
 120  124       */
 121  125      public boolean weakCompareAndSet(V       expectedReference,
 122  126                                       V       newReference,
 123  127                                       boolean expectedMark,
 124  128                                       boolean newMark) {
 125      -        ReferenceBooleanPair<V> current = atomicRef.get();
 126      -        return  expectedReference == current.reference &&
 127      -            expectedMark == current.bit &&
 128      -            ((newReference == current.reference && newMark == current.bit) ||
 129      -             atomicRef.weakCompareAndSet(current,
 130      -                                     new ReferenceBooleanPair<V>(newReference,
 131      -                                                              newMark)));
      129 +        return compareAndSet(expectedReference, newReference,
      130 +                             expectedMark, newMark);
 132  131      }
 133  132  
 134  133      /**
 135  134       * Atomically sets the value of both the reference and mark
 136  135       * to the given update values if the
 137  136       * current reference is {@code ==} to the expected reference
 138  137       * and the current mark is equal to the expected mark.
 139  138       *
 140  139       * @param expectedReference the expected value of the reference
 141  140       * @param newReference the new value for the reference
 142  141       * @param expectedMark the expected value of the mark
 143  142       * @param newMark the new value for the mark
 144  143       * @return true if successful
 145  144       */
 146  145      public boolean compareAndSet(V       expectedReference,
 147  146                                   V       newReference,
 148  147                                   boolean expectedMark,
 149  148                                   boolean newMark) {
 150      -        ReferenceBooleanPair<V> current = atomicRef.get();
 151      -        return  expectedReference == current.reference &&
 152      -            expectedMark == current.bit &&
 153      -            ((newReference == current.reference && newMark == current.bit) ||
 154      -             atomicRef.compareAndSet(current,
 155      -                                     new ReferenceBooleanPair<V>(newReference,
 156      -                                                              newMark)));
      149 +        Pair<V> current = pair;
      150 +        return
      151 +            expectedReference == current.reference &&
      152 +            expectedMark == current.mark &&
      153 +            ((newReference == current.reference &&
      154 +              newMark == current.mark) ||
      155 +             casPair(current, Pair.of(newReference, newMark)));
 157  156      }
 158  157  
 159  158      /**
 160  159       * Unconditionally sets the value of both the reference and mark.
 161  160       *
 162  161       * @param newReference the new value for the reference
 163  162       * @param newMark the new value for the mark
 164  163       */
 165  164      public void set(V newReference, boolean newMark) {
 166      -        ReferenceBooleanPair<V> current = atomicRef.get();
 167      -        if (newReference != current.reference || newMark != current.bit)
 168      -            atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark));
      165 +        Pair<V> current = pair;
      166 +        if (newReference != current.reference || newMark != current.mark)
      167 +            this.pair = Pair.of(newReference, newMark);
 169  168      }
 170  169  
 171  170      /**
 172  171       * Atomically sets the value of the mark to the given update value
 173  172       * if the current reference is {@code ==} to the expected
 174  173       * reference.  Any given invocation of this operation may fail
 175  174       * (return {@code false}) spuriously, but repeated invocation
 176  175       * when the current value holds the expected value and no other
 177  176       * thread is also attempting to set the value will eventually
 178  177       * succeed.
 179  178       *
 180  179       * @param expectedReference the expected value of the reference
 181  180       * @param newMark the new value for the mark
 182  181       * @return true if successful
 183  182       */
 184  183      public boolean attemptMark(V expectedReference, boolean newMark) {
 185      -        ReferenceBooleanPair<V> current = atomicRef.get();
 186      -        return  expectedReference == current.reference &&
 187      -            (newMark == current.bit ||
 188      -             atomicRef.compareAndSet
 189      -             (current, new ReferenceBooleanPair<V>(expectedReference,
 190      -                                                newMark)));
      184 +        Pair<V> current = pair;
      185 +        return
      186 +            expectedReference == current.reference &&
      187 +            (newMark == current.mark ||
      188 +             casPair(current, Pair.of(expectedReference, newMark)));
 191  189      }
      190 +
      191 +    // Unsafe mechanics
      192 +
      193 +    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
      194 +    private static final long pairOffset =
      195 +        objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
      196 +
      197 +    private boolean casPair(Pair<V> cmp, Pair<V> val) {
      198 +        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
      199 +    }
      200 +
      201 +    static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
      202 +                                  String field, Class<?> klazz) {
      203 +        try {
      204 +            return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
      205 +        } catch (NoSuchFieldException e) {
      206 +            // Convert Exception to corresponding Error
      207 +            NoSuchFieldError error = new NoSuchFieldError(field);
      208 +            error.initCause(e);
      209 +            throw error;
      210 +        }
      211 +    }
 192  212  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX