1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 /* 26 * This file is available under and governed by the GNU General Public 27 * License version 2 only, as published by the Free Software Foundation. 28 * However, the following notice accompanied the original version of this 29 * file: 30 * 31 * Written by Doug Lea with assistance from members of JCP JSR-166 32 * Expert Group and released to the public domain, as explained at 33 * http://creativecommons.org/publicdomain/zero/1.0/ 34 */ 35 36 package java.util.concurrent.atomic; 37 import java.io.IOException; 38 import java.io.Serializable; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 import java.util.function.DoubleBinaryOperator; 42 43 /** 44 * One or more variables that together maintain a running {@code double} 45 * value updated using a supplied function. When updates (method 46 * {@link #accumulate}) are contended across threads, the set of variables 47 * may grow dynamically to reduce contention. Method {@link #get} 48 * (or, equivalently, {@link #doubleValue}) returns the current value 49 * across the variables maintaining updates. 50 * 51 * <p>The supplied accumulator function must be side-effect-free. It 52 * may be re-applied when attempted updates fail due to contention 53 * among threads. The function is applied with the current value as 54 * its first argument, and the given update as the second argument. 55 * For example, to maintain a running maximum value, you could supply 56 * {@code (x, y) -> (y > x) ? y : x} along with {@code 57 * Double.MINIMUM_VALUE} as the identity. (Class {@link DoubleAdder} 58 * provides analogs of the functionality of this class for the common 59 * special case of maintaining sums.) 60 * 61 * <p>This class extends {@link Number}, but does <em>not</em> define 62 * methods such as {@code hashCode} and {@code compareTo} because 63 * instances are expected to be mutated, and so are not useful as 64 * collection keys. 65 * 66 * @since 1.8 67 * @author Doug Lea 68 */ 69 public class DoubleAccumulator extends Striped64 implements Serializable { 70 private static final long serialVersionUID = 7249069246863182397L; 71 72 private final DoubleBinaryOperator function; 73 private final long identity; // use long representation 74 75 /** 76 * Creates a new instance using the given accumulator function 77 * and identity element. 78 */ 79 public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction, 80 double identity) { 81 this.function = accumulatorFunction; 82 base = this.identity = Double.doubleToRawLongBits(identity); 83 } 84 85 /** 86 * Updates with the given value. 87 * 88 * @param x the value 89 */ 90 public void accumulate(double x) { 91 Cell[] as; long b, v, r; CellHashCode hc; Cell a; int m; 92 if ((as = cells) != null || 93 (r = Double.doubleToRawLongBits 94 (function.operateAsDouble // ## rename when JDK8 syncs with lambda, applyAsDouble 95 (Double.longBitsToDouble(b = base), x))) != b && !casBase(b, r)) { 96 boolean uncontended = true; 97 if ((hc = threadCellHashCode.get()) == null || 98 as == null || (m = as.length - 1) < 0 || 99 (a = as[m & hc.code]) == null || 100 !(uncontended = 101 (r = Double.doubleToRawLongBits 102 (function.operateAsDouble // ## rename when JDK8 syncs with lambda, applyAsDouble 103 (Double.longBitsToDouble(v = a.value), x))) == v || 104 a.cas(v, r))) 105 doubleAccumulate(x, hc, function, uncontended); 106 } 107 } 108 109 /** 110 * Returns the current value. The returned value is 111 * <em>NOT</em> an atomic snapshot: Invocation in the absence of 112 * concurrent updates returns an accurate result, but concurrent 113 * updates that occur while the value is being calculated might 114 * not be incorporated. 115 * 116 * @return the current value 117 */ 118 public double get() { 119 Cell[] as = cells; Cell a; 120 double result = Double.longBitsToDouble(base); 121 if (as != null) { 122 for (int i = 0; i < as.length; ++i) { 123 if ((a = as[i]) != null) 124 result = function.operateAsDouble // ## rename when JDK8 syncs with lambda, applyAsDouble 125 (result, Double.longBitsToDouble(a.value)); 126 } 127 } 128 return result; 129 } 130 131 /** 132 * Resets variables maintaining updates the given value. This 133 * method may be a useful alternative to creating a new updater, 134 * but is only effective if there are no concurrent updates. 135 * Because this method is intrinsically racy, it should only be 136 * used when it is known that no threads are concurrently 137 * updating. 138 */ 139 public void reset() { 140 Cell[] as = cells; Cell a; 141 base = identity; 142 if (as != null) { 143 for (int i = 0; i < as.length; ++i) { 144 if ((a = as[i]) != null) 145 a.value = identity; 146 } 147 } 148 } 149 150 /** 151 * Equivalent in effect to {@link #get} followed by {@link 152 * #reset}. This method may apply for example during quiescent 153 * points between multithreaded computations. If there are 154 * updates concurrent with this method, the returned value is 155 * <em>not</em> guaranteed to be the final value occurring before 156 * the reset. 157 * 158 * @return the value before reset 159 */ 160 public double getThenReset() { 161 Cell[] as = cells; Cell a; 162 double result = Double.longBitsToDouble(base); 163 base = identity; 164 if (as != null) { 165 for (int i = 0; i < as.length; ++i) { 166 if ((a = as[i]) != null) { 167 double v = Double.longBitsToDouble(a.value); 168 a.value = identity; 169 result = function.operateAsDouble(result, v); // ## rename when JDK8 syncs with lambda, applyAsDouble 170 } 171 } 172 } 173 return result; 174 } 175 176 /** 177 * Returns the String representation of the {@link #sum}. 178 * @return the String representation of the {@link #sum} 179 */ 180 public String toString() { 181 return Double.toString(get()); 182 } 183 184 /** 185 * Equivalent to {@link #sum}. 186 * 187 * @return the sum 188 */ 189 public double doubleValue() { 190 return get(); 191 } 192 193 /** 194 * Returns the {@link #sum} as a {@code long} after a 195 * narrowing primitive conversion. 196 */ 197 public long longValue() { 198 return (long)get(); 199 } 200 201 /** 202 * Returns the {@link #sum} as an {@code int} after a 203 * narrowing primitive conversion. 204 */ 205 public int intValue() { 206 return (int)get(); 207 } 208 209 /** 210 * Returns the {@link #sum} as a {@code float} 211 * after a narrowing primitive conversion. 212 */ 213 public float floatValue() { 214 return (float)get(); 215 } 216 217 private void writeObject(java.io.ObjectOutputStream s) 218 throws java.io.IOException { 219 s.defaultWriteObject(); 220 s.writeDouble(get()); 221 } 222 223 private void readObject(ObjectInputStream s) 224 throws IOException, ClassNotFoundException { 225 s.defaultReadObject(); 226 cellsBusy = 0; 227 cells = null; 228 base = Double.doubleToRawLongBits(s.readDouble()); 229 } 230 231 }