1. /*
  2. * @(#)AtomicLongFieldUpdater.java 1.6 04/02/13
  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. import sun.misc.Unsafe;
  9. import java.lang.reflect.*;
  10. /**
  11. * A reflection-based utility that enables atomic updates to
  12. * designated <tt>volatile long</tt> fields of designated classes.
  13. * This class is designed for use in atomic data structures in which
  14. * several fields of the same node are independently subject to atomic
  15. * updates.
  16. *
  17. * <p> Note that the guarantees of the <tt>compareAndSet</tt> method
  18. * in this class are weaker than in other atomic classes. Because this
  19. * class cannot ensure that all uses of the field are appropriate for
  20. * purposes of atomic access, it can guarantee atomicity and volatile
  21. * semantics only with respect to other invocations of
  22. * <tt>compareAndSet</tt> and <tt>set</tt>.
  23. *
  24. * @since 1.5
  25. * @author Doug Lea
  26. * @param <T> The type of the object holding the updatable field
  27. */
  28. public abstract class AtomicLongFieldUpdater<T> {
  29. /**
  30. * Creates an updater for objects with the given field. The Class
  31. * argument is needed to check that reflective types and generic
  32. * types match.
  33. * @param tclass the class of the objects holding the field
  34. * @param fieldName the name of the field to be updated.
  35. * @return the updater
  36. * @throws IllegalArgumentException if the field is not a
  37. * volatile long type.
  38. * @throws RuntimeException with a nested reflection-based
  39. * exception if the class does not hold field or is the wrong type.
  40. */
  41. public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
  42. if (AtomicLong.VM_SUPPORTS_LONG_CAS)
  43. return new CASUpdater<U>(tclass, fieldName);
  44. else
  45. return new LockedUpdater<U>(tclass, fieldName);
  46. }
  47. /**
  48. * Protected do-nothing constructor for use by subclasses.
  49. */
  50. protected AtomicLongFieldUpdater() {
  51. }
  52. /**
  53. * Atomically set the value of the field of the given object managed
  54. * by this Updater to the given updated value if the current value
  55. * <tt>==</tt> the expected value. This method is guaranteed to be
  56. * atomic with respect to other calls to <tt>compareAndSet</tt> and
  57. * <tt>set</tt>, but not necessarily with respect to other
  58. * changes in the field.
  59. * @param obj An object whose field to conditionally set
  60. * @param expect the expected value
  61. * @param update the new value
  62. * @return true if successful.
  63. * @throws ClassCastException if <tt>obj</tt> is not an instance
  64. * of the class possessing the field established in the constructor.
  65. */
  66. public abstract boolean compareAndSet(T obj, long expect, long update);
  67. /**
  68. * Atomically set the value of the field of the given object managed
  69. * by this Updater to the given updated value if the current value
  70. * <tt>==</tt> the expected value. This method is guaranteed to be
  71. * atomic with respect to other calls to <tt>compareAndSet</tt> and
  72. * <tt>set</tt>, but not necessarily with respect to other
  73. * changes in the field, and may fail spuriously.
  74. * @param obj An object whose field to conditionally set
  75. * @param expect the expected value
  76. * @param update the new value
  77. * @return true if successful.
  78. * @throws ClassCastException if <tt>obj</tt> is not an instance
  79. * of the class possessing the field established in the constructor.
  80. */
  81. public abstract boolean weakCompareAndSet(T obj, long expect, long update);
  82. /**
  83. * Set the field of the given object managed by this updater. This
  84. * operation is guaranteed to act as a volatile store with respect
  85. * to subsequent invocations of <tt>compareAndSet</tt>.
  86. * @param obj An object whose field to set
  87. * @param newValue the new value
  88. */
  89. public abstract void set(T obj, long newValue);
  90. /**
  91. * Get the current value held in the field by the given object.
  92. * @param obj An object whose field to get
  93. * @return the current value
  94. */
  95. public abstract long get(T obj);
  96. /**
  97. * Set to the given value and return the old value.
  98. *
  99. * @param obj An object whose field to get and set
  100. * @param newValue the new value
  101. * @return the previous value
  102. */
  103. public long getAndSet(T obj, long newValue) {
  104. for (;;) {
  105. long current = get(obj);
  106. if (compareAndSet(obj, current, newValue))
  107. return current;
  108. }
  109. }
  110. /**
  111. * Atomically increment by one the current value.
  112. * @param obj An object whose field to get and set
  113. * @return the previous value;
  114. */
  115. public long getAndIncrement(T obj) {
  116. for (;;) {
  117. long current = get(obj);
  118. long next = current + 1;
  119. if (compareAndSet(obj, current, next))
  120. return current;
  121. }
  122. }
  123. /**
  124. * Atomically decrement by one the current value.
  125. * @param obj An object whose field to get and set
  126. * @return the previous value;
  127. */
  128. public long getAndDecrement(T obj) {
  129. for (;;) {
  130. long current = get(obj);
  131. long next = current - 1;
  132. if (compareAndSet(obj, current, next))
  133. return current;
  134. }
  135. }
  136. /**
  137. * Atomically add the given value to current value.
  138. * @param obj An object whose field to get and set
  139. * @param delta the value to add
  140. * @return the previous value;
  141. */
  142. public long getAndAdd(T obj, long delta) {
  143. for (;;) {
  144. long current = get(obj);
  145. long next = current + delta;
  146. if (compareAndSet(obj, current, next))
  147. return current;
  148. }
  149. }
  150. /**
  151. * Atomically increment by one the current value.
  152. * @param obj An object whose field to get and set
  153. * @return the updated value;
  154. */
  155. public long incrementAndGet(T obj) {
  156. for (;;) {
  157. long current = get(obj);
  158. long next = current + 1;
  159. if (compareAndSet(obj, current, next))
  160. return next;
  161. }
  162. }
  163. /**
  164. * Atomically decrement by one the current value.
  165. * @param obj An object whose field to get and set
  166. * @return the updated value;
  167. */
  168. public long decrementAndGet(T obj) {
  169. for (;;) {
  170. long current = get(obj);
  171. long next = current - 1;
  172. if (compareAndSet(obj, current, next))
  173. return next;
  174. }
  175. }
  176. /**
  177. * Atomically add the given value to current value.
  178. * @param obj An object whose field to get and set
  179. * @param delta the value to add
  180. * @return the updated value;
  181. */
  182. public long addAndGet(T obj, long delta) {
  183. for (;;) {
  184. long current = get(obj);
  185. long next = current + delta;
  186. if (compareAndSet(obj, current, next))
  187. return next;
  188. }
  189. }
  190. private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
  191. private static final Unsafe unsafe = Unsafe.getUnsafe();
  192. private final long offset;
  193. private final Class<T> tclass;
  194. CASUpdater(Class<T> tclass, String fieldName) {
  195. Field field = null;
  196. try {
  197. field = tclass.getDeclaredField(fieldName);
  198. } catch(Exception ex) {
  199. throw new RuntimeException(ex);
  200. }
  201. Class fieldt = field.getType();
  202. if (fieldt != long.class)
  203. throw new IllegalArgumentException("Must be long type");
  204. if (!Modifier.isVolatile(field.getModifiers()))
  205. throw new IllegalArgumentException("Must be volatile type");
  206. this.tclass = tclass;
  207. offset = unsafe.objectFieldOffset(field);
  208. }
  209. public boolean compareAndSet(T obj, long expect, long update) {
  210. if (!tclass.isInstance(obj))
  211. throw new ClassCastException();
  212. return unsafe.compareAndSwapLong(obj, offset, expect, update);
  213. }
  214. public boolean weakCompareAndSet(T obj, long expect, long update) {
  215. if (!tclass.isInstance(obj))
  216. throw new ClassCastException();
  217. return unsafe.compareAndSwapLong(obj, offset, expect, update);
  218. }
  219. public void set(T obj, long newValue) {
  220. if (!tclass.isInstance(obj))
  221. throw new ClassCastException();
  222. unsafe.putLongVolatile(obj, offset, newValue);
  223. }
  224. public long get(T obj) {
  225. if (!tclass.isInstance(obj))
  226. throw new ClassCastException();
  227. return unsafe.getLongVolatile(obj, offset);
  228. }
  229. }
  230. private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
  231. private static final Unsafe unsafe = Unsafe.getUnsafe();
  232. private final long offset;
  233. private final Class<T> tclass;
  234. LockedUpdater(Class<T> tclass, String fieldName) {
  235. Field field = null;
  236. try {
  237. field = tclass.getDeclaredField(fieldName);
  238. } catch(Exception ex) {
  239. throw new RuntimeException(ex);
  240. }
  241. Class fieldt = field.getType();
  242. if (fieldt != long.class)
  243. throw new IllegalArgumentException("Must be long type");
  244. if (!Modifier.isVolatile(field.getModifiers()))
  245. throw new IllegalArgumentException("Must be volatile type");
  246. this.tclass = tclass;
  247. offset = unsafe.objectFieldOffset(field);
  248. }
  249. public boolean compareAndSet(T obj, long expect, long update) {
  250. if (!tclass.isInstance(obj))
  251. throw new ClassCastException();
  252. synchronized(this) {
  253. long v = unsafe.getLong(obj, offset);
  254. if (v != expect)
  255. return false;
  256. unsafe.putLong(obj, offset, update);
  257. return true;
  258. }
  259. }
  260. public boolean weakCompareAndSet(T obj, long expect, long update) {
  261. return compareAndSet(obj, expect, update);
  262. }
  263. public void set(T obj, long newValue) {
  264. if (!tclass.isInstance(obj))
  265. throw new ClassCastException();
  266. synchronized(this) {
  267. unsafe.putLong(obj, offset, newValue);
  268. }
  269. }
  270. public long get(T obj) {
  271. if (!tclass.isInstance(obj))
  272. throw new ClassCastException();
  273. synchronized(this) {
  274. return unsafe.getLong(obj, offset);
  275. }
  276. }
  277. }
  278. }