AtomicMarkableReference.java revision 8eb35c835be1345d3873a82cc9e42f944d698afd
1/* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/licenses/publicdomain 5 */ 6 7package java.util.concurrent.atomic; 8 9import sun.misc.Unsafe; 10 11/** 12 * An {@code AtomicMarkableReference} maintains an object reference 13 * along with a mark bit, that can be updated atomically. 14 * 15 * <p>Implementation note: This implementation maintains markable 16 * references by creating internal objects representing "boxed" 17 * [reference, boolean] pairs. 18 * 19 * @since 1.5 20 * @author Doug Lea 21 * @param <V> The type of object referred to by this reference 22 */ 23public class AtomicMarkableReference<V> { 24 25 private static class Pair<T> { 26 final T reference; 27 final boolean mark; 28 private Pair(T reference, boolean mark) { 29 this.reference = reference; 30 this.mark = mark; 31 } 32 static <T> Pair<T> of(T reference, boolean mark) { 33 return new Pair<T>(reference, mark); 34 } 35 } 36 37 private volatile Pair<V> pair; 38 39 /** 40 * Creates a new {@code AtomicMarkableReference} with the given 41 * initial values. 42 * 43 * @param initialRef the initial reference 44 * @param initialMark the initial mark 45 */ 46 public AtomicMarkableReference(V initialRef, boolean initialMark) { 47 pair = Pair.of(initialRef, initialMark); 48 } 49 50 /** 51 * Returns the current value of the reference. 52 * 53 * @return the current value of the reference 54 */ 55 public V getReference() { 56 return pair.reference; 57 } 58 59 /** 60 * Returns the current value of the mark. 61 * 62 * @return the current value of the mark 63 */ 64 public boolean isMarked() { 65 return pair.mark; 66 } 67 68 /** 69 * Returns the current values of both the reference and the mark. 70 * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }. 71 * 72 * @param markHolder an array of size of at least one. On return, 73 * {@code markholder[0]} will hold the value of the mark. 74 * @return the current value of the reference 75 */ 76 public V get(boolean[] markHolder) { 77 Pair<V> pair = this.pair; 78 markHolder[0] = pair.mark; 79 return pair.reference; 80 } 81 82 /** 83 * Atomically sets the value of both the reference and mark 84 * to the given update values if the 85 * current reference is {@code ==} to the expected reference 86 * and the current mark is equal to the expected mark. 87 * 88 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 89 * and does not provide ordering guarantees, so is only rarely an 90 * appropriate alternative to {@code compareAndSet}. 91 * 92 * @param expectedReference the expected value of the reference 93 * @param newReference the new value for the reference 94 * @param expectedMark the expected value of the mark 95 * @param newMark the new value for the mark 96 * @return true if successful 97 */ 98 public boolean weakCompareAndSet(V expectedReference, 99 V newReference, 100 boolean expectedMark, 101 boolean newMark) { 102 return compareAndSet(expectedReference, newReference, 103 expectedMark, 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 {@code ==} 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, 119 V newReference, 120 boolean expectedMark, 121 boolean newMark) { 122 Pair<V> current = pair; 123 return 124 expectedReference == current.reference && 125 expectedMark == current.mark && 126 ((newReference == current.reference && 127 newMark == current.mark) || 128 casPair(current, Pair.of(newReference, newMark))); 129 } 130 131 /** 132 * Unconditionally sets the value of both the reference and mark. 133 * 134 * @param newReference the new value for the reference 135 * @param newMark the new value for the mark 136 */ 137 public void set(V newReference, boolean newMark) { 138 Pair<V> current = pair; 139 if (newReference != current.reference || newMark != current.mark) 140 this.pair = Pair.of(newReference, newMark); 141 } 142 143 /** 144 * Atomically sets the value of the mark to the given update value 145 * if the current reference is {@code ==} to the expected 146 * reference. Any given invocation of this operation may fail 147 * (return {@code false}) spuriously, but repeated invocation 148 * when the current value holds the expected value and no other 149 * thread is also attempting to set the value will eventually 150 * succeed. 151 * 152 * @param expectedReference the expected value of the reference 153 * @param newMark the new value for the mark 154 * @return true if successful 155 */ 156 public boolean attemptMark(V expectedReference, boolean newMark) { 157 Pair<V> current = pair; 158 return 159 expectedReference == current.reference && 160 (newMark == current.mark || 161 casPair(current, Pair.of(expectedReference, newMark))); 162 } 163 164 // Unsafe mechanics 165 166 private static final sun.misc.Unsafe UNSAFE = UnsafeAccess.THE_ONE; // android-changed 167 private static final long pairOffset = 168 objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class); 169 170 private boolean casPair(Pair<V> cmp, Pair<V> val) { 171 return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); 172 } 173 174 static long objectFieldOffset(sun.misc.Unsafe UNSAFE, 175 String field, Class<?> klazz) { 176 try { 177 return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field)); 178 } catch (NoSuchFieldException e) { 179 // Convert Exception to corresponding Error 180 NoSuchFieldError error = new NoSuchFieldError(field); 181 error.initCause(e); 182 throw error; 183 } 184 } 185} 186