001/* 002 * Written by Doug Lea with assistance from members of JCP JSR-166 003 * Expert Group and released to the public domain, as explained at 004 * http://creativecommons.org/publicdomain/zero/1.0/ 005 * 006 * Source: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/DoubleAdder.java?revision=1.12 007 */ 008 009package io.prometheus.client; 010 011import java.io.IOException; 012import java.io.ObjectInputStream; 013import java.io.ObjectOutputStream; 014import java.io.Serializable; 015 016/** 017 * One or more variables that together maintain an initially zero 018 * {@code double} sum. When updates (method {@link #add}) are 019 * contended across threads, the set of variables may grow dynamically 020 * to reduce contention. Method {@link #sum} (or, equivalently {@link 021 * #doubleValue}) returns the current total combined across the 022 * variables maintaining the sum. 023 * 024 * <p>This class extends {@link Number}, but does <em>not</em> define 025 * methods such as {@code equals}, {@code hashCode} and {@code 026 * compareTo} because instances are expected to be mutated, and so are 027 * not useful as collection keys. 028 * 029 * <p><em>jsr166e note: This class is targeted to be placed in 030 * java.util.concurrent.atomic.</em> 031 * 032 * @since 1.8 033 * @author Doug Lea 034 */ 035public class DoubleAdder extends Striped64 implements Serializable { 036 private static final long serialVersionUID = 7249069246863182397L; 037 038 /** 039 * Update function. Note that we must use "long" for underlying 040 * representations, because there is no compareAndSet for double, 041 * due to the fact that the bitwise equals used in any CAS 042 * implementation is not the same as double-precision equals. 043 * However, we use CAS only to detect and alleviate contention, 044 * for which bitwise equals works best anyway. In principle, the 045 * long/double conversions used here should be essentially free on 046 * most platforms since they just re-interpret bits. 047 * 048 * Similar conversions are used in other methods. 049 */ 050 final long fn(long v, long x) { 051 return Double.doubleToRawLongBits 052 (Double.longBitsToDouble(v) + 053 Double.longBitsToDouble(x)); 054 } 055 056 /** 057 * Creates a new adder with initial sum of zero. 058 */ 059 public DoubleAdder() { 060 } 061 062 /** 063 * Adds the given value. 064 * 065 * @param x the value to add 066 */ 067 public void add(double x) { 068 Cell[] as; long b, v; int[] hc; Cell a; int n; 069 if ((as = cells) != null || 070 !casBase(b = base, 071 Double.doubleToRawLongBits 072 (Double.longBitsToDouble(b) + x))) { 073 boolean uncontended = true; 074 if ((hc = threadHashCode.get()) == null || 075 as == null || (n = as.length) < 1 || 076 (a = as[(n - 1) & hc[0]]) == null || 077 !(uncontended = a.cas(v = a.value, 078 Double.doubleToRawLongBits 079 (Double.longBitsToDouble(v) + x)))) 080 retryUpdate(Double.doubleToRawLongBits(x), hc, uncontended); 081 } 082 } 083 084 /** 085 * Returns the current sum. The returned value is <em>NOT</em> an 086 * atomic snapshot; invocation in the absence of concurrent 087 * updates returns an accurate result, but concurrent updates that 088 * occur while the sum is being calculated might not be 089 * incorporated. Also, because floating-point arithmetic is not 090 * strictly associative, the returned result need not be identical 091 * to the value that would be obtained in a sequential series of 092 * updates to a single variable. 093 * 094 * @return the sum 095 */ 096 public double sum() { 097 Cell[] as = cells; 098 double sum = Double.longBitsToDouble(base); 099 if (as != null) { 100 int n = as.length; 101 for (int i = 0; i < n; ++i) { 102 Cell a = as[i]; 103 if (a != null) 104 sum += Double.longBitsToDouble(a.value); 105 } 106 } 107 return sum; 108 } 109 110 /** 111 * Resets variables maintaining the sum to zero. This method may 112 * be a useful alternative to creating a new adder, but is only 113 * effective if there are no concurrent updates. Because this 114 * method is intrinsically racy, it should only be used when it is 115 * known that no threads are concurrently updating. 116 */ 117 public void reset() { 118 internalReset(0L); 119 } 120 121 /** 122 * Equivalent in effect to {@link #sum} followed by {@link 123 * #reset}. This method may apply for example during quiescent 124 * points between multithreaded computations. If there are 125 * updates concurrent with this method, the returned value is 126 * <em>not</em> guaranteed to be the final value occurring before 127 * the reset. 128 * 129 * @return the sum 130 */ 131 public double sumThenReset() { 132 Cell[] as = cells; 133 double sum = Double.longBitsToDouble(base); 134 base = 0L; 135 if (as != null) { 136 int n = as.length; 137 for (int i = 0; i < n; ++i) { 138 Cell a = as[i]; 139 if (a != null) { 140 long v = a.value; 141 a.value = 0L; 142 sum += Double.longBitsToDouble(v); 143 } 144 } 145 } 146 return sum; 147 } 148 149 /** 150 * Returns the String representation of the {@link #sum}. 151 * @return the String representation of the {@link #sum} 152 */ 153 public String toString() { 154 return Double.toString(sum()); 155 } 156 157 /** 158 * Equivalent to {@link #sum}. 159 * 160 * @return the sum 161 */ 162 public double doubleValue() { 163 return sum(); 164 } 165 166 /** 167 * Returns the {@link #sum} as a {@code long} after a 168 * narrowing primitive conversion. 169 */ 170 public long longValue() { 171 return (long)sum(); 172 } 173 174 /** 175 * Returns the {@link #sum} as an {@code int} after a 176 * narrowing primitive conversion. 177 */ 178 public int intValue() { 179 return (int)sum(); 180 } 181 182 /** 183 * Returns the {@link #sum} as a {@code float} 184 * after a narrowing primitive conversion. 185 */ 186 public float floatValue() { 187 return (float)sum(); 188 } 189 190 private void writeObject(ObjectOutputStream s) throws IOException { 191 s.defaultWriteObject(); 192 s.writeDouble(sum()); 193 } 194 195 private void readObject(ObjectInputStream s) 196 throws IOException, ClassNotFoundException { 197 s.defaultReadObject(); 198 busy = 0; 199 cells = null; 200 base = Double.doubleToRawLongBits(s.readDouble()); 201 } 202 203}