1. /*
  2. * @(#)AtomicStampedReference.java 1.4 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.concurrent.atomic;
  8. /**
  9. * An <tt>AtomicStampedReference</tt> maintains an object reference
  10. * along with an integer "stamp", that can be updated atomically.
  11. *
  12. * <p> Implementation note. This implementation maintains stamped
  13. * references by creating internal objects representing "boxed"
  14. * [reference, integer] pairs.
  15. *
  16. * @since 1.5
  17. * @author Doug Lea
  18. * @param <V> The type of object referred to by this reference
  19. */
  20. public class AtomicStampedReference<V> {
  21. private static class ReferenceIntegerPair<T> {
  22. private final T reference;
  23. private final int integer;
  24. ReferenceIntegerPair(T r, int i) {
  25. reference = r; integer = i;
  26. }
  27. }
  28. private final AtomicReference<ReferenceIntegerPair<V>> atomicRef;
  29. /**
  30. * Creates a new <tt>AtomicStampedReference</tt> with the given
  31. * initial values.
  32. *
  33. * @param initialRef the initial reference
  34. * @param initialStamp the initial stamp
  35. */
  36. public AtomicStampedReference(V initialRef, int initialStamp) {
  37. atomicRef = new AtomicReference<ReferenceIntegerPair<V>>
  38. (new ReferenceIntegerPair<V>(initialRef, initialStamp));
  39. }
  40. /**
  41. * Returns the current value of the reference.
  42. *
  43. * @return the current value of the reference
  44. */
  45. public V getReference() {
  46. return atomicRef.get().reference;
  47. }
  48. /**
  49. * Returns the current value of the stamp.
  50. *
  51. * @return the current value of the stamp
  52. */
  53. public int getStamp() {
  54. return atomicRef.get().integer;
  55. }
  56. /**
  57. * Returns the current values of both the reference and the stamp.
  58. * Typical usage is <tt>int[1] holder; ref = v.get(holder); </tt>.
  59. *
  60. * @param stampHolder an array of size of at least one. On return,
  61. * <tt>stampholder[0]</tt> will hold the value of the stamp.
  62. * @return the current value of the reference
  63. */
  64. public V get(int[] stampHolder) {
  65. ReferenceIntegerPair<V> p = atomicRef.get();
  66. stampHolder[0] = p.integer;
  67. return p.reference;
  68. }
  69. /**
  70. * Atomically sets the value of both the reference and stamp
  71. * to the given update values if the
  72. * current reference is <tt>==</tt> to the expected reference
  73. * and the current stamp is equal to the expected stamp. Any given
  74. * invocation of this operation may fail (return
  75. * <tt>false</tt>) spuriously, but repeated invocation when
  76. * the current value holds the expected value and no other thread
  77. * is also attempting to set the value will eventually succeed.
  78. *
  79. * @param expectedReference the expected value of the reference
  80. * @param newReference the new value for the reference
  81. * @param expectedStamp the expected value of the stamp
  82. * @param newStamp the new value for the stamp
  83. * @return true if successful
  84. */
  85. public boolean weakCompareAndSet(V expectedReference,
  86. V newReference,
  87. int expectedStamp,
  88. int newStamp) {
  89. ReferenceIntegerPair current = atomicRef.get();
  90. return expectedReference == current.reference &&
  91. expectedStamp == current.integer &&
  92. ((newReference == current.reference &&
  93. newStamp == current.integer) ||
  94. atomicRef.weakCompareAndSet(current,
  95. new ReferenceIntegerPair<V>(newReference,
  96. newStamp)));
  97. }
  98. /**
  99. * Atomically sets the value of both the reference and stamp
  100. * to the given update values if the
  101. * current reference is <tt>==</tt> to the expected reference
  102. * and the current stamp is equal to the expected stamp.
  103. *
  104. * @param expectedReference the expected value of the reference
  105. * @param newReference the new value for the reference
  106. * @param expectedStamp the expected value of the stamp
  107. * @param newStamp the new value for the stamp
  108. * @return true if successful
  109. */
  110. public boolean compareAndSet(V expectedReference,
  111. V newReference,
  112. int expectedStamp,
  113. int newStamp) {
  114. ReferenceIntegerPair current = atomicRef.get();
  115. return expectedReference == current.reference &&
  116. expectedStamp == current.integer &&
  117. ((newReference == current.reference &&
  118. newStamp == current.integer) ||
  119. atomicRef.compareAndSet(current,
  120. new ReferenceIntegerPair<V>(newReference,
  121. newStamp)));
  122. }
  123. /**
  124. * Unconditionally sets the value of both the reference and stamp.
  125. *
  126. * @param newReference the new value for the reference
  127. * @param newStamp the new value for the stamp
  128. */
  129. public void set(V newReference, int newStamp) {
  130. ReferenceIntegerPair current = atomicRef.get();
  131. if (newReference != current.reference || newStamp != current.integer)
  132. atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp));
  133. }
  134. /**
  135. * Atomically sets the value of the stamp to the given update value
  136. * if the current reference is <tt>==</tt> to the expected
  137. * reference. Any given invocation of this operation may fail
  138. * (return <tt>false</tt>) spuriously, but repeated invocation
  139. * when the current value holds the expected value and no other
  140. * thread is also attempting to set the value will eventually
  141. * succeed.
  142. *
  143. * @param expectedReference the expected value of the reference
  144. * @param newStamp the new value for the stamp
  145. * @return true if successful
  146. */
  147. public boolean attemptStamp(V expectedReference, int newStamp) {
  148. ReferenceIntegerPair current = atomicRef.get();
  149. return expectedReference == current.reference &&
  150. (newStamp == current.integer ||
  151. atomicRef.compareAndSet(current,
  152. new ReferenceIntegerPair<V>(expectedReference,
  153. newStamp)));
  154. }
  155. }