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