ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/atomic/DoubleAccumulator.java
Revision: 1.44
Committed: Fri Nov 27 17:43:34 2020 UTC (3 years, 6 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.43: +3 -2 lines
Log Message:
Incorporate snippets code improvements from Pavel Rappo

File Contents

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