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 jsr166;
8 
9 import java.util.concurrent.CyclicBarrier;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.ExecutorService;
12 import java.util.concurrent.atomic.DoubleAdder;
13 
14 import junit.framework.Test;
15 import junit.framework.TestSuite;
16 
17 public class DoubleAdderTest extends JSR166TestCase {
18     // android-note: Removed because the CTS runner does a bad job of
19     // retrying tests that have suite() declarations.
20     //
21     // public static void main(String[] args) {
22     //     main(suite(), args);
23     // }
24     // public static Test suite() {
25     //     return new TestSuite(DoubleAdderTest.class);
26     // }
27 
28     /**
29      * default constructed initializes to zero
30      */
testConstructor()31     public void testConstructor() {
32         DoubleAdder ai = new DoubleAdder();
33         assertEquals(0.0, ai.sum());
34     }
35 
36     /**
37      * add adds given value to current, and sum returns current value
38      */
testAddAndSum()39     public void testAddAndSum() {
40         DoubleAdder ai = new DoubleAdder();
41         ai.add(2.0);
42         assertEquals(2.0, ai.sum());
43         ai.add(-4.0);
44         assertEquals(-2.0, ai.sum());
45     }
46 
47     /**
48      * reset() causes subsequent sum() to return zero
49      */
testReset()50     public void testReset() {
51         DoubleAdder ai = new DoubleAdder();
52         ai.add(2.0);
53         assertEquals(2.0, ai.sum());
54         ai.reset();
55         assertEquals(0.0, ai.sum());
56     }
57 
58     /**
59      * sumThenReset() returns sum; subsequent sum() returns zero
60      */
testSumThenReset()61     public void testSumThenReset() {
62         DoubleAdder ai = new DoubleAdder();
63         ai.add(2.0);
64         assertEquals(2.0, ai.sum());
65         assertEquals(2.0, ai.sumThenReset());
66         assertEquals(0.0, ai.sum());
67     }
68 
69     /**
70      * a deserialized serialized adder holds same value
71      */
testSerialization()72     public void testSerialization() throws Exception {
73         DoubleAdder x = new DoubleAdder();
74         DoubleAdder y = serialClone(x);
75         assertNotSame(x, y);
76         x.add(-22.0);
77         DoubleAdder z = serialClone(x);
78         assertEquals(-22.0, x.sum());
79         assertEquals(0.0, y.sum());
80         assertEquals(-22.0, z.sum());
81     }
82 
83     /**
84      * toString returns current value.
85      */
testToString()86     public void testToString() {
87         DoubleAdder ai = new DoubleAdder();
88         assertEquals(Double.toString(0.0), ai.toString());
89         ai.add(1.0);
90         assertEquals(Double.toString(1.0), ai.toString());
91     }
92 
93     /**
94      * intValue returns current value.
95      */
testIntValue()96     public void testIntValue() {
97         DoubleAdder ai = new DoubleAdder();
98         assertEquals(0, ai.intValue());
99         ai.add(1.0);
100         assertEquals(1, ai.intValue());
101     }
102 
103     /**
104      * longValue returns current value.
105      */
testLongValue()106     public void testLongValue() {
107         DoubleAdder ai = new DoubleAdder();
108         assertEquals(0, ai.longValue());
109         ai.add(1.0);
110         assertEquals(1, ai.longValue());
111     }
112 
113     /**
114      * floatValue returns current value.
115      */
testFloatValue()116     public void testFloatValue() {
117         DoubleAdder ai = new DoubleAdder();
118         assertEquals(0.0f, ai.floatValue());
119         ai.add(1.0);
120         assertEquals(1.0f, ai.floatValue());
121     }
122 
123     /**
124      * doubleValue returns current value.
125      */
testDoubleValue()126     public void testDoubleValue() {
127         DoubleAdder ai = new DoubleAdder();
128         assertEquals(0.0, ai.doubleValue());
129         ai.add(1.0);
130         assertEquals(1.0, ai.doubleValue());
131     }
132 
133     /**
134      * adds by multiple threads produce correct sum
135      */
testAddAndSumMT()136     public void testAddAndSumMT() throws Throwable {
137         final int incs = 1000000;
138         final int nthreads = 4;
139         final ExecutorService pool = Executors.newCachedThreadPool();
140         DoubleAdder a = new DoubleAdder();
141         CyclicBarrier barrier = new CyclicBarrier(nthreads + 1);
142         for (int i = 0; i < nthreads; ++i)
143             pool.execute(new AdderTask(a, barrier, incs));
144         barrier.await();
145         barrier.await();
146         double total = (long)nthreads * incs;
147         double sum = a.sum();
148         assertEquals(sum, total);
149         pool.shutdown();
150     }
151 
152     static final class AdderTask implements Runnable {
153         final DoubleAdder adder;
154         final CyclicBarrier barrier;
155         final int incs;
156         volatile double result;
AdderTask(DoubleAdder adder, CyclicBarrier barrier, int incs)157         AdderTask(DoubleAdder adder, CyclicBarrier barrier, int incs) {
158             this.adder = adder;
159             this.barrier = barrier;
160             this.incs = incs;
161         }
162 
run()163         public void run() {
164             try {
165                 barrier.await();
166                 DoubleAdder a = adder;
167                 for (int i = 0; i < incs; ++i)
168                     a.add(1.0);
169                 result = a.sum();
170                 barrier.await();
171             } catch (Throwable t) { throw new Error(t); }
172         }
173     }
174 
175 }
176