| /* |
| * Written by Doug Lea with assistance from members of JCP JSR-166 |
| * Expert Group and released to the public domain, as explained at |
| * http://creativecommons.org/publicdomain/zero/1.0/ |
| */ |
| |
| package jsr166; |
| |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.atomic.LongAdder; |
| |
| import junit.framework.Test; |
| import junit.framework.TestSuite; |
| |
| public class LongAdderTest extends JSR166TestCase { |
| // android-note: Removed because the CTS runner does a bad job of |
| // retrying tests that have suite() declarations. |
| // |
| // public static void main(String[] args) { |
| // main(suite(), args); |
| // } |
| // public static Test suite() { |
| // return new TestSuite(LongAdderTest.class); |
| // } |
| |
| /** |
| * default constructed initializes to zero |
| */ |
| public void testConstructor() { |
| LongAdder ai = new LongAdder(); |
| assertEquals(0, ai.sum()); |
| } |
| |
| /** |
| * add adds given value to current, and sum returns current value |
| */ |
| public void testAddAndSum() { |
| LongAdder ai = new LongAdder(); |
| ai.add(2); |
| assertEquals(2, ai.sum()); |
| ai.add(-4); |
| assertEquals(-2, ai.sum()); |
| } |
| |
| /** |
| * decrement decrements and sum returns current value |
| */ |
| public void testDecrementAndsum() { |
| LongAdder ai = new LongAdder(); |
| ai.decrement(); |
| assertEquals(-1, ai.sum()); |
| ai.decrement(); |
| assertEquals(-2, ai.sum()); |
| } |
| |
| /** |
| * incrementAndGet increments and returns current value |
| */ |
| public void testIncrementAndsum() { |
| LongAdder ai = new LongAdder(); |
| ai.increment(); |
| assertEquals(1, ai.sum()); |
| ai.increment(); |
| assertEquals(2, ai.sum()); |
| } |
| |
| /** |
| * reset() causes subsequent sum() to return zero |
| */ |
| public void testReset() { |
| LongAdder ai = new LongAdder(); |
| ai.add(2); |
| assertEquals(2, ai.sum()); |
| ai.reset(); |
| assertEquals(0, ai.sum()); |
| } |
| |
| /** |
| * sumThenReset() returns sum; subsequent sum() returns zero |
| */ |
| public void testSumThenReset() { |
| LongAdder ai = new LongAdder(); |
| ai.add(2); |
| assertEquals(2, ai.sum()); |
| assertEquals(2, ai.sumThenReset()); |
| assertEquals(0, ai.sum()); |
| } |
| |
| /** |
| * a deserialized serialized adder holds same value |
| */ |
| public void testSerialization() throws Exception { |
| LongAdder x = new LongAdder(); |
| LongAdder y = serialClone(x); |
| assertNotSame(x, y); |
| x.add(-22); |
| LongAdder z = serialClone(x); |
| assertNotSame(y, z); |
| assertEquals(-22, x.sum()); |
| assertEquals(0, y.sum()); |
| assertEquals(-22, z.sum()); |
| } |
| |
| /** |
| * toString returns current value. |
| */ |
| public void testToString() { |
| LongAdder ai = new LongAdder(); |
| assertEquals("0", ai.toString()); |
| ai.increment(); |
| assertEquals(Long.toString(1), ai.toString()); |
| } |
| |
| /** |
| * intValue returns current value. |
| */ |
| public void testIntValue() { |
| LongAdder ai = new LongAdder(); |
| assertEquals(0, ai.intValue()); |
| ai.increment(); |
| assertEquals(1, ai.intValue()); |
| } |
| |
| /** |
| * longValue returns current value. |
| */ |
| public void testLongValue() { |
| LongAdder ai = new LongAdder(); |
| assertEquals(0, ai.longValue()); |
| ai.increment(); |
| assertEquals(1, ai.longValue()); |
| } |
| |
| /** |
| * floatValue returns current value. |
| */ |
| public void testFloatValue() { |
| LongAdder ai = new LongAdder(); |
| assertEquals(0.0f, ai.floatValue()); |
| ai.increment(); |
| assertEquals(1.0f, ai.floatValue()); |
| } |
| |
| /** |
| * doubleValue returns current value. |
| */ |
| public void testDoubleValue() { |
| LongAdder ai = new LongAdder(); |
| assertEquals(0.0, ai.doubleValue()); |
| ai.increment(); |
| assertEquals(1.0, ai.doubleValue()); |
| } |
| |
| /** |
| * adds by multiple threads produce correct sum |
| */ |
| public void testAddAndSumMT() throws Throwable { |
| final int incs = 1000000; |
| final int nthreads = 4; |
| final ExecutorService pool = Executors.newCachedThreadPool(); |
| LongAdder a = new LongAdder(); |
| CyclicBarrier barrier = new CyclicBarrier(nthreads + 1); |
| for (int i = 0; i < nthreads; ++i) |
| pool.execute(new AdderTask(a, barrier, incs)); |
| barrier.await(); |
| barrier.await(); |
| long total = (long)nthreads * incs; |
| long sum = a.sum(); |
| assertEquals(sum, total); |
| pool.shutdown(); |
| } |
| |
| static final class AdderTask implements Runnable { |
| final LongAdder adder; |
| final CyclicBarrier barrier; |
| final int incs; |
| volatile long result; |
| AdderTask(LongAdder adder, CyclicBarrier barrier, int incs) { |
| this.adder = adder; |
| this.barrier = barrier; |
| this.incs = incs; |
| } |
| |
| public void run() { |
| try { |
| barrier.await(); |
| LongAdder a = adder; |
| for (int i = 0; i < incs; ++i) |
| a.add(1L); |
| result = a.sum(); |
| barrier.await(); |
| } catch (Throwable t) { throw new Error(t); } |
| } |
| } |
| |
| } |