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