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 165 166 167 168
/* * @(#)AtomicStampedReference.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 AtomicStampedReference} maintains an object reference * along with an integer "stamp", that can be updated atomically. * * <p> Implementation note. This implementation maintains stamped * references by creating internal objects representing "boxed" * [reference, integer] pairs. * * @since 1.5 * @author Doug Lea * @param <V> The type of object referred to by this reference */ public class AtomicStampedReference<V> { private static class ReferenceIntegerPair<T> { private final T reference; private final int integer; ReferenceIntegerPair(T r, int i) { reference = r; integer = i; } } private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; /** * Creates a new {@code AtomicStampedReference} with the given * initial values. * * @param initialRef the initial reference * @param initialStamp the initial stamp */ public AtomicStampedReference(V initialRef, int initialStamp) { atomicRef = new AtomicReference<ReferenceIntegerPair<V>> (new ReferenceIntegerPair<V>(initialRef, initialStamp)); } /** * 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 stamp. * * @return the current value of the stamp */ public int getStamp() { return atomicRef.get().integer; } /** * Returns the current values of both the reference and the stamp. * Typical usage is {@code int[1] holder; ref = v.get(holder); }. * * @param stampHolder an array of size of at least one. On return, * {@code stampholder[0]} will hold the value of the stamp. * @return the current value of the reference */ public V get(int[] stampHolder) { ReferenceIntegerPair<V> p = atomicRef.get(); stampHolder[0] = p.integer; return p.reference; } /** * Atomically sets the value of both the reference and stamp * to the given update values if the * current reference is {@code ==} to the expected reference * and the current stamp is equal to the expected stamp. * * <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 expectedStamp the expected value of the stamp * @param newStamp the new value for the stamp * @return true if successful */ public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ReferenceIntegerPair<V> current = atomicRef.get(); return expectedReference == current.reference && expectedStamp == current.integer && ((newReference == current.reference && newStamp == current.integer) || atomicRef.weakCompareAndSet(current, new ReferenceIntegerPair<V>(newReference, newStamp))); } /** * Atomically sets the value of both the reference and stamp * to the given update values if the * current reference is {@code ==} to the expected reference * and the current stamp is equal to the expected stamp. * * @param expectedReference the expected value of the reference * @param newReference the new value for the reference * @param expectedStamp the expected value of the stamp * @param newStamp the new value for the stamp * @return true if successful */ public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) { ReferenceIntegerPair<V> current = atomicRef.get(); return expectedReference == current.reference && expectedStamp == current.integer && ((newReference == current.reference && newStamp == current.integer) || atomicRef.compareAndSet(current, new ReferenceIntegerPair<V>(newReference, newStamp))); } /** * Unconditionally sets the value of both the reference and stamp. * * @param newReference the new value for the reference * @param newStamp the new value for the stamp */ public void set(V newReference, int newStamp) { ReferenceIntegerPair<V> current = atomicRef.get(); if (newReference != current.reference || newStamp != current.integer) atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); } /** * Atomically sets the value of the stamp 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 newStamp the new value for the stamp * @return true if successful */ public boolean attemptStamp(V expectedReference, int newStamp) { ReferenceIntegerPair<V> current = atomicRef.get(); return expectedReference == current.reference && (newStamp == current.integer || atomicRef.compareAndSet(current, new ReferenceIntegerPair<V>(expectedReference, newStamp))); } }