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
7package java.util.concurrent.atomic;
8
9import java.io.Serializable;
10import 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 */
50public 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     */
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     */
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     */
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     */
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     */
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     */
160    public String toString() {
161        return Double.toString(get());
162    }
163
164    /**
165     * Equivalent to {@link #get}.
166     *
167     * @return the current value
168     */
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     */
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     */
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     */
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
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         */
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     */
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     */
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