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