1   /*
2    * %W% %E%
3    *
4    * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6    */
7   
8   package java.util.concurrent.atomic;
9   import sun.misc.Unsafe;
10  
11  /**
12   * A {@code long} value that may be updated atomically.  See the
13   * {@link java.util.concurrent.atomic} package specification for
14   * description of the properties of atomic variables. An
15   * {@code AtomicLong} is used in applications such as atomically
16   * incremented sequence numbers, and cannot be used as a replacement
17   * for a {@link java.lang.Long}. However, this class does extend
18   * {@code Number} to allow uniform access by tools and utilities that
19   * deal with numerically-based classes.
20   *
21   * @since 1.5
22   * @author Doug Lea
23   */
24  public class AtomicLong extends Number implements java.io.Serializable {
25      private static final long serialVersionUID = 1927816293512124184L;
26  
27      // setup to use Unsafe.compareAndSwapLong for updates
28      private static final Unsafe unsafe = Unsafe.getUnsafe();
29      private static final long valueOffset;
30  
31      /**
32       * Records whether the underlying JVM supports lockless
33       * CompareAndSet for longs. While the unsafe.CompareAndSetLong
34       * method works in either case, some constructions should be
35       * handled at Java level to avoid locking user-visible locks.
36       */
37      static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
38  
39      /**
40       * Returns whether underlying JVM supports lockless CompareAndSet
41       * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
42       */
43      private static native boolean VMSupportsCS8();
44  
45      static {
46        try {
47          valueOffset = unsafe.objectFieldOffset
48              (AtomicLong.class.getDeclaredField("value"));
49        } catch (Exception ex) { throw new Error(ex); }
50      }
51  
52      private volatile long value;
53  
54      /**
55       * Creates a new AtomicLong with the given initial value.
56       *
57       * @param initialValue the initial value
58       */
59      public AtomicLong(long initialValue) {
60          value = initialValue;
61      }
62  
63      /**
64       * Creates a new AtomicLong with initial value {@code 0}.
65       */
66      public AtomicLong() {
67      }
68  
69      /**
70       * Gets the current value.
71       *
72       * @return the current value
73       */
74      public final long get() {
75          return value;
76      }
77  
78      /**
79       * Sets to the given value.
80       *
81       * @param newValue the new value
82       */
83      public final void set(long newValue) {
84          value = newValue;
85      }
86  
87      /**
88       * Eventually sets to the given value.
89       *
90       * @param newValue the new value
91       * @since 1.6
92       */
93      public final void lazySet(long newValue) {
94          unsafe.putOrderedLong(this, valueOffset, newValue);
95      }
96  
97      /**
98       * Atomically sets to the given value and returns the old value.
99       *
100      * @param newValue the new value
101      * @return the previous value
102      */
103     public final long getAndSet(long newValue) {
104         while (true) {
105             long current = get();
106             if (compareAndSet(current, newValue))
107                 return current;
108         }
109     }
110 
111     /**
112      * Atomically sets the value to the given updated value
113      * if the current value {@code ==} the expected value.
114      *
115      * @param expect the expected value
116      * @param update the new value
117      * @return true if successful. False return indicates that
118      * the actual value was not equal to the expected value.
119      */
120     public final boolean compareAndSet(long expect, long update) {
121     return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
122     }
123 
124     /**
125      * Atomically sets the value to the given updated value
126      * if the current value {@code ==} the expected value.
127      *
128      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
129      * and does not provide ordering guarantees, so is only rarely an
130      * appropriate alternative to {@code compareAndSet}.
131      *
132      * @param expect the expected value
133      * @param update the new value
134      * @return true if successful.
135      */
136     public final boolean weakCompareAndSet(long expect, long update) {
137     return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
138     }
139 
140     /**
141      * Atomically increments by one the current value.
142      *
143      * @return the previous value
144      */
145     public final long getAndIncrement() {
146         while (true) {
147             long current = get();
148             long next = current + 1;
149             if (compareAndSet(current, next))
150                 return current;
151         }
152     }
153 
154     /**
155      * Atomically decrements by one the current value.
156      *
157      * @return the previous value
158      */
159     public final long getAndDecrement() {
160         while (true) {
161             long current = get();
162             long next = current - 1;
163             if (compareAndSet(current, next))
164                 return current;
165         }
166     }
167 
168     /**
169      * Atomically adds the given value to the current value.
170      *
171      * @param delta the value to add
172      * @return the previous value
173      */
174     public final long getAndAdd(long delta) {
175         while (true) {
176             long current = get();
177             long next = current + delta;
178             if (compareAndSet(current, next))
179                 return current;
180         }
181     }
182 
183     /**
184      * Atomically increments by one the current value.
185      *
186      * @return the updated value
187      */
188     public final long incrementAndGet() {
189         for (;;) {
190             long current = get();
191             long next = current + 1;
192             if (compareAndSet(current, next))
193                 return next;
194         }
195     }
196 
197     /**
198      * Atomically decrements by one the current value.
199      *
200      * @return the updated value
201      */
202     public final long decrementAndGet() {
203         for (;;) {
204             long current = get();
205             long next = current - 1;
206             if (compareAndSet(current, next))
207                 return next;
208         }
209     }
210 
211     /**
212      * Atomically adds the given value to the current value.
213      *
214      * @param delta the value to add
215      * @return the updated value
216      */
217     public final long addAndGet(long delta) {
218         for (;;) {
219             long current = get();
220             long next = current + delta;
221             if (compareAndSet(current, next))
222                 return next;
223         }
224     }
225 
226     /**
227      * Returns the String representation of the current value.
228      * @return the String representation of the current value.
229      */
230     public String toString() {
231         return Long.toString(get());
232     }
233 
234 
235     public int intValue() {
236     return (int)get();
237     }
238 
239     public long longValue() {
240     return (long)get();
241     }
242 
243     public float floatValue() {
244     return (float)get();
245     }
246 
247     public double doubleValue() {
248     return (double)get();
249     }
250 
251 }
252