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.LongAdder;
13 
14 import junit.framework.Test;
15 import junit.framework.TestSuite;
16 
17 public class LongAdderTest 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(LongAdderTest.class);
26     // }
27 
28     /**
29      * default constructed initializes to zero
30      */
testConstructor()31     public void testConstructor() {
32         LongAdder ai = new LongAdder();
33         assertEquals(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         LongAdder ai = new LongAdder();
41         ai.add(2);
42         assertEquals(2, ai.sum());
43         ai.add(-4);
44         assertEquals(-2, ai.sum());
45     }
46 
47     /**
48      * decrement decrements and sum returns current value
49      */
testDecrementAndsum()50     public void testDecrementAndsum() {
51         LongAdder ai = new LongAdder();
52         ai.decrement();
53         assertEquals(-1, ai.sum());
54         ai.decrement();
55         assertEquals(-2, ai.sum());
56     }
57 
58     /**
59      * incrementAndGet increments and returns current value
60      */
testIncrementAndsum()61     public void testIncrementAndsum() {
62         LongAdder ai = new LongAdder();
63         ai.increment();
64         assertEquals(1, ai.sum());
65         ai.increment();
66         assertEquals(2, ai.sum());
67     }
68 
69     /**
70      * reset() causes subsequent sum() to return zero
71      */
testReset()72     public void testReset() {
73         LongAdder ai = new LongAdder();
74         ai.add(2);
75         assertEquals(2, ai.sum());
76         ai.reset();
77         assertEquals(0, ai.sum());
78     }
79 
80     /**
81      * sumThenReset() returns sum; subsequent sum() returns zero
82      */
testSumThenReset()83     public void testSumThenReset() {
84         LongAdder ai = new LongAdder();
85         ai.add(2);
86         assertEquals(2, ai.sum());
87         assertEquals(2, ai.sumThenReset());
88         assertEquals(0, ai.sum());
89     }
90 
91     /**
92      * a deserialized serialized adder holds same value
93      */
testSerialization()94     public void testSerialization() throws Exception {
95         LongAdder x = new LongAdder();
96         LongAdder y = serialClone(x);
97         assertNotSame(x, y);
98         x.add(-22);
99         LongAdder z = serialClone(x);
100         assertNotSame(y, z);
101         assertEquals(-22, x.sum());
102         assertEquals(0, y.sum());
103         assertEquals(-22, z.sum());
104     }
105 
106     /**
107      * toString returns current value.
108      */
testToString()109     public void testToString() {
110         LongAdder ai = new LongAdder();
111         assertEquals("0", ai.toString());
112         ai.increment();
113         assertEquals(Long.toString(1), ai.toString());
114     }
115 
116     /**
117      * intValue returns current value.
118      */
testIntValue()119     public void testIntValue() {
120         LongAdder ai = new LongAdder();
121         assertEquals(0, ai.intValue());
122         ai.increment();
123         assertEquals(1, ai.intValue());
124     }
125 
126     /**
127      * longValue returns current value.
128      */
testLongValue()129     public void testLongValue() {
130         LongAdder ai = new LongAdder();
131         assertEquals(0, ai.longValue());
132         ai.increment();
133         assertEquals(1, ai.longValue());
134     }
135 
136     /**
137      * floatValue returns current value.
138      */
testFloatValue()139     public void testFloatValue() {
140         LongAdder ai = new LongAdder();
141         assertEquals(0.0f, ai.floatValue());
142         ai.increment();
143         assertEquals(1.0f, ai.floatValue());
144     }
145 
146     /**
147      * doubleValue returns current value.
148      */
testDoubleValue()149     public void testDoubleValue() {
150         LongAdder ai = new LongAdder();
151         assertEquals(0.0, ai.doubleValue());
152         ai.increment();
153         assertEquals(1.0, ai.doubleValue());
154     }
155 
156     /**
157      * adds by multiple threads produce correct sum
158      */
testAddAndSumMT()159     public void testAddAndSumMT() throws Throwable {
160         final int incs = 1000000;
161         final int nthreads = 4;
162         final ExecutorService pool = Executors.newCachedThreadPool();
163         LongAdder a = new LongAdder();
164         CyclicBarrier barrier = new CyclicBarrier(nthreads + 1);
165         for (int i = 0; i < nthreads; ++i)
166             pool.execute(new AdderTask(a, barrier, incs));
167         barrier.await();
168         barrier.await();
169         long total = (long)nthreads * incs;
170         long sum = a.sum();
171         assertEquals(sum, total);
172         pool.shutdown();
173     }
174 
175     static final class AdderTask implements Runnable {
176         final LongAdder adder;
177         final CyclicBarrier barrier;
178         final int incs;
179         volatile long result;
AdderTask(LongAdder adder, CyclicBarrier barrier, int incs)180         AdderTask(LongAdder adder, CyclicBarrier barrier, int incs) {
181             this.adder = adder;
182             this.barrier = barrier;
183             this.incs = incs;
184         }
185 
run()186         public void run() {
187             try {
188                 barrier.await();
189                 LongAdder a = adder;
190                 for (int i = 0; i < incs; ++i)
191                     a.add(1L);
192                 result = a.sum();
193                 barrier.await();
194             } catch (Throwable t) { throw new Error(t); }
195         }
196     }
197 
198 }
199