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.LongBinaryOperator; 42 43 /** 44 * One or more variables that together maintain a running {@code long} 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 #longValue}) 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 * Long.MINIMUM_VALUE} as the identity. (Class {@link LongAdder} 58 * provides analogs of the functionality of this class for the common 59 * special case of maintaining counts and 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 LongAccumulator extends Striped64 implements Serializable { 70 private static final long serialVersionUID = 7249069246863182397L; 71 72 private final LongBinaryOperator function; 73 private final long identity; 74 75 /** 76 * Creates a new instance using the given accumulator function 77 * and identity element. 78 */ 79 public LongAccumulator(LongBinaryOperator accumulatorFunction, 80 long identity) { 81 this.function = accumulatorFunction; 82 base = this.identity = identity; 83 } 84 85 /** 86 * Updates with the given value. 87 * 88 * @param x the value 89 */ 90 public void accumulate(long x) { 91 Cell[] as; long b, v, r; CellHashCode hc; Cell a; int m; 92 if ((as = cells) != null || 93 (r = function.operateAsLong(b = base, x)) != b && !casBase(b, r)) { // ## rename when JDK8 syncs with lambda, applyAsLong 94 boolean uncontended = true; 95 if ((hc = threadCellHashCode.get()) == null || 96 as == null || (m = as.length - 1) < 0 || 97 (a = as[m & hc.code]) == null || 98 !(uncontended = 99 (r = function.operateAsLong(v = a.value, x)) == v || // ## rename when JDK8 syncs with lambda, applyAsLong 100 a.cas(v, r))) 101 longAccumulate(x, hc, function, uncontended); 102 } 103 } 104 105 /** 106 * Returns the current value. The returned value is 107 * <em>NOT</em> an atomic snapshot: Invocation in the absence of 108 * concurrent updates returns an accurate result, but concurrent 109 * updates that occur while the value is being calculated might 110 * not be incorporated. 111 * 112 * @return the current value 113 */ 114 public long get() { 115 Cell[] as = cells; Cell a; 116 long result = base; 117 if (as != null) { 118 for (int i = 0; i < as.length; ++i) { 119 if ((a = as[i]) != null) 120 result = function.operateAsLong(result, a.value); // ## rename when JDK8 syncs with lambda, applyAsLong 121 } 122 } 123 return result; 124 } 125 126 /** 127 * Resets variables maintaining updates the given value. This 128 * method may be a useful alternative to creating a new updater, 129 * but is only effective if there are no concurrent updates. 130 * Because this method is intrinsically racy, it should only be 131 * used when it is known that no threads are concurrently 132 * updating. 133 */ 134 public void reset() { 135 Cell[] as = cells; Cell a; 136 base = identity; 137 if (as != null) { 138 for (int i = 0; i < as.length; ++i) { 139 if ((a = as[i]) != null) 140 a.value = identity; 141 } 142 } 143 } 144 145 /** 146 * Equivalent in effect to {@link #get} followed by {@link 147 * #reset}. This method may apply for example during quiescent 148 * points between multithreaded computations. If there are 149 * updates concurrent with this method, the returned value is 150 * <em>not</em> guaranteed to be the final value occurring before 151 * the reset. 152 * 153 * @return the value before reset 154 */ 155 public long getThenReset() { 156 Cell[] as = cells; Cell a; 157 long result = base; 158 base = identity; 159 if (as != null) { 160 for (int i = 0; i < as.length; ++i) { 161 if ((a = as[i]) != null) { 162 long v = a.value; 163 a.value = identity; 164 result = function.operateAsLong(result, v); // ## rename when JDK8 syncs with lambda, applyAsLong 165 } 166 } 167 } 168 return result; 169 } 170 171 /** 172 * Returns the String representation of the current value. 173 * @return the String representation of the current value 174 */ 175 public String toString() { 176 return Long.toString(get()); 177 } 178 179 /** 180 * Equivalent to {@link #get}. 181 * 182 * @return the maximum 183 */ 184 public long longValue() { 185 return get(); 186 } 187 188 /** 189 * Returns the {@link #get} as an {@code int} after a narrowing 190 * primitive conversion. 191 */ 192 public int intValue() { 193 return (int)get(); 194 } 195 196 /** 197 * Returns the {@link #get} as a {@code float} 198 * after a widening primitive conversion. 199 */ 200 public float floatValue() { 201 return (float)get(); 202 } 203 204 /** 205 * Returns the {@link #get} as a {@code double} after a widening 206 * primitive conversion. 207 */ 208 public double doubleValue() { 209 return (double)get(); 210 } 211 212 private void writeObject(java.io.ObjectOutputStream s) 213 throws java.io.IOException { 214 s.defaultWriteObject(); 215 s.writeLong(get()); 216 } 217 218 private void readObject(ObjectInputStream s) 219 throws IOException, ClassNotFoundException { 220 s.defaultReadObject(); 221 cellsBusy = 0; 222 cells = null; 223 base = s.readLong(); 224 } 225 226 }