• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/publicdomain/zero/1.0/
5  */
6 
7 package java.util.concurrent.atomic;
8 
9 import java.io.Serializable;
10 import java.util.function.LongBinaryOperator;
11 
12 /**
13  * One or more variables that together maintain a running {@code long}
14  * value updated using a supplied function.  When updates (method
15  * {@link #accumulate}) are contended across threads, the set of variables
16  * may grow dynamically to reduce contention.  Method {@link #get}
17  * (or, equivalently, {@link #longValue}) returns the current value
18  * across the variables maintaining updates.
19  *
20  * <p>This class is usually preferable to {@link AtomicLong} when
21  * multiple threads update a common value that is used for purposes such
22  * as collecting statistics, not for fine-grained synchronization
23  * control.  Under low update contention, the two classes have similar
24  * characteristics. But under high contention, expected throughput of
25  * this class is significantly higher, at the expense of higher space
26  * consumption.
27  *
28  * <p>The order of accumulation within or across threads is not
29  * guaranteed and cannot be depended upon, so this class is only
30  * applicable to functions for which the order of accumulation does
31  * not matter. The supplied accumulator function should be
32  * side-effect-free, since it may be re-applied when attempted updates
33  * fail due to contention among threads. The function is applied with
34  * the current value as its first argument, and the given update as
35  * the second argument.  For example, to maintain a running maximum
36  * value, you could supply {@code Long::max} along with {@code
37  * Long.MIN_VALUE} as the identity.
38  *
39  * <p>Class {@link LongAdder} provides analogs of the functionality of
40  * this class for the common special case of maintaining counts and
41  * sums.  The call {@code new LongAdder()} is equivalent to {@code new
42  * LongAccumulator((x, y) -> x + y, 0L}.
43  *
44  * <p>This class extends {@link Number}, but does <em>not</em> define
45  * methods such as {@code equals}, {@code hashCode} and {@code
46  * compareTo} because instances are expected to be mutated, and so are
47  * not useful as collection keys.
48  *
49  * @since 1.8
50  * @author Doug Lea
51  */
52 public class LongAccumulator extends Striped64 implements Serializable {
53     private static final long serialVersionUID = 7249069246863182397L;
54 
55     private final LongBinaryOperator function;
56     private final long identity;
57 
58     /**
59      * Creates a new instance using the given accumulator function
60      * and identity element.
61      * @param accumulatorFunction a side-effect-free function of two arguments
62      * @param identity identity (initial value) for the accumulator function
63      */
LongAccumulator(LongBinaryOperator accumulatorFunction, long identity)64     public LongAccumulator(LongBinaryOperator accumulatorFunction,
65                            long identity) {
66         this.function = accumulatorFunction;
67         base = this.identity = identity;
68     }
69 
70     /**
71      * Updates with the given value.
72      *
73      * @param x the value
74      */
accumulate(long x)75     public void accumulate(long x) {
76         Cell[] as; long b, v, r; int m; Cell a;
77         if ((as = cells) != null ||
78             (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {
79             boolean uncontended = true;
80             if (as == null || (m = as.length - 1) < 0 ||
81                 (a = as[getProbe() & m]) == null ||
82                 !(uncontended =
83                   (r = function.applyAsLong(v = a.value, x)) == v ||
84                   a.cas(v, r)))
85                 longAccumulate(x, function, uncontended);
86         }
87     }
88 
89     /**
90      * Returns the current value.  The returned value is <em>NOT</em>
91      * an atomic snapshot; invocation in the absence of concurrent
92      * updates returns an accurate result, but concurrent updates that
93      * occur while the value is being calculated might not be
94      * incorporated.
95      *
96      * @return the current value
97      */
get()98     public long get() {
99         Cell[] as = cells;
100         long result = base;
101         if (as != null) {
102             for (Cell a : as)
103                 if (a != null)
104                     result = function.applyAsLong(result, a.value);
105         }
106         return result;
107     }
108 
109     /**
110      * Resets variables maintaining updates to the identity value.
111      * This method may be a useful alternative to creating a new
112      * updater, but is only effective if there are no concurrent
113      * updates.  Because this method is intrinsically racy, it should
114      * only be used when it is known that no threads are concurrently
115      * updating.
116      */
reset()117     public void reset() {
118         Cell[] as = cells;
119         base = identity;
120         if (as != null) {
121             for (Cell a : as)
122                 if (a != null)
123                     a.reset(identity);
124         }
125     }
126 
127     /**
128      * Equivalent in effect to {@link #get} followed by {@link
129      * #reset}. This method may apply for example during quiescent
130      * points between multithreaded computations.  If there are
131      * updates concurrent with this method, the returned value is
132      * <em>not</em> guaranteed to be the final value occurring before
133      * the reset.
134      *
135      * @return the value before reset
136      */
getThenReset()137     public long getThenReset() {
138         Cell[] as = cells;
139         long result = base;
140         base = identity;
141         if (as != null) {
142             for (Cell a : as) {
143                 if (a != null) {
144                     long v = a.value;
145                     a.reset(identity);
146                     result = function.applyAsLong(result, v);
147                 }
148             }
149         }
150         return result;
151     }
152 
153     /**
154      * Returns the String representation of the current value.
155      * @return the String representation of the current value
156      */
toString()157     public String toString() {
158         return Long.toString(get());
159     }
160 
161     /**
162      * Equivalent to {@link #get}.
163      *
164      * @return the current value
165      */
longValue()166     public long longValue() {
167         return get();
168     }
169 
170     /**
171      * Returns the {@linkplain #get current value} as an {@code int}
172      * after a narrowing primitive conversion.
173      */
intValue()174     public int intValue() {
175         return (int)get();
176     }
177 
178     /**
179      * Returns the {@linkplain #get current value} as a {@code float}
180      * after a widening primitive conversion.
181      */
floatValue()182     public float floatValue() {
183         return (float)get();
184     }
185 
186     /**
187      * Returns the {@linkplain #get current value} as a {@code double}
188      * after a widening primitive conversion.
189      */
doubleValue()190     public double doubleValue() {
191         return (double)get();
192     }
193 
194     /**
195      * Serialization proxy, used to avoid reference to the non-public
196      * Striped64 superclass in serialized forms.
197      * @serial include
198      */
199     private static class SerializationProxy implements Serializable {
200         private static final long serialVersionUID = 7249069246863182397L;
201 
202         /**
203          * The current value returned by get().
204          * @serial
205          */
206         private final long value;
207 
208         /**
209          * The function used for updates.
210          * @serial
211          */
212         private final LongBinaryOperator function;
213 
214         /**
215          * The identity value.
216          * @serial
217          */
218         private final long identity;
219 
SerializationProxy(long value, LongBinaryOperator function, long identity)220         SerializationProxy(long value,
221                            LongBinaryOperator function,
222                            long identity) {
223             this.value = value;
224             this.function = function;
225             this.identity = identity;
226         }
227 
228         /**
229          * Returns a {@code LongAccumulator} object with initial state
230          * held by this proxy.
231          *
232          * @return a {@code LongAccumulator} object with initial state
233          * held by this proxy
234          */
readResolve()235         private Object readResolve() {
236             LongAccumulator a = new LongAccumulator(function, identity);
237             a.base = value;
238             return a;
239         }
240     }
241 
242     /**
243      * Returns a
244      * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
245      * SerializationProxy</a>
246      * representing the state of this instance.
247      *
248      * @return a {@link SerializationProxy}
249      * representing the state of this instance
250      */
writeReplace()251     private Object writeReplace() {
252         return new SerializationProxy(get(), function, identity);
253     }
254 
255     /**
256      * @param s the stream
257      * @throws java.io.InvalidObjectException always
258      */
readObject(java.io.ObjectInputStream s)259     private void readObject(java.io.ObjectInputStream s)
260         throws java.io.InvalidObjectException {
261         throw new java.io.InvalidObjectException("Proxy required");
262     }
263 
264 }
265