ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/DoubleAdder.java
Revision: 1.1
Committed: Tue Aug 2 18:04:12 2011 UTC (12 years, 8 months ago) by dl
Branch: MAIN
Log Message:
Refactor and introduce new forms of update

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 jsr166e;
8 import java.io.IOException;
9 import java.io.Serializable;
10 import java.io.ObjectInputStream;
11 import java.io.ObjectOutputStream;
12
13 /**
14 * One or more variables that together maintain an initially zero
15 * {@code double} sum. When updates (method {@link #add}) are
16 * contended across threads, the set of variables may grow dynamically
17 * to reduce contention. Method {@link #sum} (or, equivalently {@link
18 * #doubleValue}) returns the current total combined across the
19 * variables maintaining the sum.
20 *
21 * <p>This class extends {@link Number}, but does <em>not</em> define
22 * methods such as {@code hashCode} and {@code compareTo} because
23 * instances are expected to be mutated, and so are not useful as
24 * collection keys.
25 *
26 * <p><em>jsr166e note: This class is targeted to be placed in
27 * java.util.concurrent.atomic<em>
28 *
29 * @author Doug Lea
30 */
31 public class DoubleAdder extends Striped64 implements Serializable {
32 private static final long serialVersionUID = 7249069246863182397L;
33
34 /**
35 * Update function. Note that we must use "long" for underlying
36 * representations, because there is no compareAndSet for double,
37 * due to the fact that the bitwise equals used in any CAS
38 * implementation is not the same as double-precision equals.
39 * However, we use CAS only to detect and alleviate contention,
40 * for which bitwise equals works best anyway. In principle, the
41 * long/double conversions used here should be essentially free on
42 * most platforms since they just re-interpret bits.
43 *
44 * Similar conversions are used in other methods.
45 */
46 final long fn(long v, long x) {
47 return Double.doubleToRawLongBits
48 (Double.longBitsToDouble(v) +
49 Double.longBitsToDouble(x));
50 }
51
52 /**
53 * Creates a new adder with initial sum of zero.
54 */
55 public DoubleAdder() {
56 }
57
58 /**
59 * Adds the given value.
60 *
61 * @param x the value to add
62 */
63 public void add(double x) {
64 Cell[] as; long b, v; HashCode hc; Cell a; int n;
65 if ((as = cells) != null ||
66 !casBase(b = base,
67 Double.doubleToRawLongBits
68 (Double.longBitsToDouble(b) + x))) {
69 boolean uncontended = true;
70 int h = (hc = threadHashCode.get()).code;
71 if (as == null || (n = as.length) < 1 ||
72 (a = as[(n - 1) & h]) == null ||
73 !(uncontended = a.cas(v = a.value,
74 Double.doubleToRawLongBits
75 (Double.longBitsToDouble(v) + x))))
76 retryUpdate(Double.doubleToRawLongBits(x), hc, uncontended);
77 }
78 }
79
80 /**
81 * Returns the current sum. The returned value is <em>NOT</em> an
82 * atomic snapshot: Invocation in the absence of concurrent
83 * updates returns an accurate result, but concurrent updates that
84 * occur while the sum is being calculated might not be
85 * incorporated. Also, because double-precision arithmetic is not
86 * strictly associative, the returned result need not be identical
87 * to the value that would be obtained in a sequential series of
88 * updates to a single variable.
89 *
90 * @return the sum
91 */
92 public double sum() {
93 Cell[] as = cells;
94 double sum = Double.longBitsToDouble(base);
95 if (as != null) {
96 int n = as.length;
97 for (int i = 0; i < n; ++i) {
98 Cell a = as[i];
99 if (a != null)
100 sum += Double.longBitsToDouble(a.value);
101 }
102 }
103 return sum;
104 }
105
106 /**
107 * Resets variables maintaining the sum to zero. This method may
108 * be a useful alternative to creating a new adder, but is only
109 * effective if there are no concurrent updates. Because this
110 * method is intrinsically racy, it should only be used when it is
111 * known that no threads are concurrently updating.
112 */
113 public void reset() {
114 internalReset(0L);
115 }
116
117 /**
118 * Equivalent in effect to {@link #sum} followed by {@link
119 * #reset}. This method may apply for example during quiescent
120 * points between multithreaded computations. If there are
121 * updates concurrent with this method, the returned value is
122 * <em>not</em> guaranteed to be the final value occurring before
123 * the reset.
124 *
125 * @return the sum
126 */
127 public double sumThenReset() {
128 Cell[] as = cells;
129 double sum = Double.longBitsToDouble(base);
130 base = 0L;
131 if (as != null) {
132 int n = as.length;
133 for (int i = 0; i < n; ++i) {
134 Cell a = as[i];
135 if (a != null) {
136 long v = a.value;
137 a.value = 0L;
138 sum += Double.longBitsToDouble(v);
139 }
140 }
141 }
142 return sum;
143 }
144
145 /**
146 * Returns the String representation of the {@link #sum}.
147 * @return the String representation of the {@link #sum}.
148 */
149 public String toString() {
150 return Double.toString(sum());
151 }
152
153 /**
154 * Equivalent to {@link #sum}.
155 *
156 * @return the sum
157 */
158 public double doubleValue() {
159 return sum();
160 }
161
162 /**
163 * Returns the {@link #sum} as a {@code long} after a
164 * primitive conversion.
165 */
166 public long longValue() {
167 return (long)sum();
168 }
169
170 /**
171 * Returns the {@link #sum} as an {@code int} after a
172 * primitive conversion.
173 */
174 public int intValue() {
175 return (int)sum();
176 }
177
178 /**
179 * Returns the {@link #sum} as a {@code float}
180 * after a primitive conversion.
181 */
182 public float floatValue() {
183 return (float)sum();
184 }
185
186 private void writeObject(java.io.ObjectOutputStream s)
187 throws java.io.IOException {
188 s.defaultWriteObject();
189 s.writeDouble(sum());
190 }
191
192 private void readObject(ObjectInputStream s)
193 throws IOException, ClassNotFoundException {
194 s.defaultReadObject();
195 busy = 0;
196 cells = null;
197 base = Double.doubleToRawLongBits(s.readDouble());
198 }
199
200 }