1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23/*
24 * This file is available under and governed by the GNU General Public
25 * License version 2 only, as published by the Free Software Foundation.
26 * However, the following notice accompanied the original version of this
27 * file:
28 *
29 * Written by Doug Lea with assistance from members of JCP JSR-166
30 * Expert Group and released to the public domain, as explained at
31 * http://creativecommons.org/publicdomain/zero/1.0/
32 */
33
34import java.util.concurrent.Executors;
35import java.util.concurrent.ExecutorService;
36import java.util.concurrent.Phaser;
37import java.util.concurrent.atomic.LongAccumulator;
38
39import junit.framework.Test;
40import junit.framework.TestSuite;
41
42public class LongAccumulatorTest extends JSR166TestCase {
43    public static void main(String[] args) {
44        main(suite(), args);
45    }
46    public static Test suite() {
47        return new TestSuite(LongAccumulatorTest.class);
48    }
49
50    /**
51     * default constructed initializes to zero
52     */
53    public void testConstructor() {
54        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
55        assertEquals(0, ai.get());
56    }
57
58    /**
59     * accumulate accumulates given value to current, and get returns current value
60     */
61    public void testAccumulateAndGet() {
62        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
63        ai.accumulate(2);
64        assertEquals(2, ai.get());
65        ai.accumulate(-4);
66        assertEquals(2, ai.get());
67        ai.accumulate(4);
68        assertEquals(4, ai.get());
69    }
70
71    /**
72     * reset() causes subsequent get() to return zero
73     */
74    public void testReset() {
75        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
76        ai.accumulate(2);
77        assertEquals(2, ai.get());
78        ai.reset();
79        assertEquals(0, ai.get());
80    }
81
82    /**
83     * getThenReset() returns current value; subsequent get() returns zero
84     */
85    public void testGetThenReset() {
86        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
87        ai.accumulate(2);
88        assertEquals(2, ai.get());
89        assertEquals(2, ai.getThenReset());
90        assertEquals(0, ai.get());
91    }
92
93    /**
94     * toString returns current value.
95     */
96    public void testToString() {
97        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
98        assertEquals("0", ai.toString());
99        ai.accumulate(1);
100        assertEquals(Long.toString(1), ai.toString());
101    }
102
103    /**
104     * intValue returns current value.
105     */
106    public void testIntValue() {
107        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
108        assertEquals(0, ai.intValue());
109        ai.accumulate(1);
110        assertEquals(1, ai.intValue());
111    }
112
113    /**
114     * longValue returns current value.
115     */
116    public void testLongValue() {
117        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
118        assertEquals(0, ai.longValue());
119        ai.accumulate(1);
120        assertEquals(1, ai.longValue());
121    }
122
123    /**
124     * floatValue returns current value.
125     */
126    public void testFloatValue() {
127        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
128        assertEquals(0.0f, ai.floatValue());
129        ai.accumulate(1);
130        assertEquals(1.0f, ai.floatValue());
131    }
132
133    /**
134     * doubleValue returns current value.
135     */
136    public void testDoubleValue() {
137        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
138        assertEquals(0.0, ai.doubleValue());
139        ai.accumulate(1);
140        assertEquals(1.0, ai.doubleValue());
141    }
142
143    /**
144     * accumulates by multiple threads produce correct result
145     */
146    public void testAccumulateAndGetMT() {
147        final int incs = 1000000;
148        final int nthreads = 4;
149        final ExecutorService pool = Executors.newCachedThreadPool();
150        LongAccumulator a = new LongAccumulator(Long::max, 0L);
151        Phaser phaser = new Phaser(nthreads + 1);
152        for (int i = 0; i < nthreads; ++i)
153            pool.execute(new AccTask(a, phaser, incs));
154        phaser.arriveAndAwaitAdvance();
155        phaser.arriveAndAwaitAdvance();
156        long expected = incs - 1;
157        long result = a.get();
158        assertEquals(expected, result);
159        pool.shutdown();
160    }
161
162    static final class AccTask implements Runnable {
163        final LongAccumulator acc;
164        final Phaser phaser;
165        final int incs;
166        volatile long result;
167        AccTask(LongAccumulator acc, Phaser phaser, int incs) {
168            this.acc = acc;
169            this.phaser = phaser;
170            this.incs = incs;
171        }
172
173        public void run() {
174            phaser.arriveAndAwaitAdvance();
175            LongAccumulator a = acc;
176            for (int i = 0; i < incs; ++i)
177                a.accumulate(i);
178            result = a.get();
179            phaser.arrive();
180        }
181    }
182
183}
184