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
7package jsr166;
8
9import java.util.concurrent.CyclicBarrier;
10import java.util.concurrent.Executors;
11import java.util.concurrent.ExecutorService;
12import java.util.concurrent.atomic.LongAdder;
13
14import junit.framework.Test;
15import junit.framework.TestSuite;
16
17public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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;
180        AdderTask(LongAdder adder, CyclicBarrier barrier, int incs) {
181            this.adder = adder;
182            this.barrier = barrier;
183            this.incs = incs;
184        }
185
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