--- jsr166/src/test/tck/DoubleAccumulatorTest.java 2014/12/31 19:05:42 1.3 +++ jsr166/src/test/tck/DoubleAccumulatorTest.java 2019/09/09 01:05:22 1.9 @@ -7,6 +7,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.Phaser; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.DoubleAccumulator; import junit.framework.Test; @@ -14,142 +15,137 @@ import junit.framework.TestSuite; public class DoubleAccumulatorTest extends JSR166TestCase { public static void main(String[] args) { - junit.textui.TestRunner.run(suite()); + main(suite(), args); } public static Test suite() { return new TestSuite(DoubleAccumulatorTest.class); } /** - * default constructed initializes to zero + * new instance initialized to supplied identity */ public void testConstructor() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals(0.0, ai.get()); + for (double identity : new double[] { + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.MIN_VALUE, + Double.MAX_VALUE, + 0.0, + }) + assertEquals(identity, + new DoubleAccumulator(Double::max, identity).get()); } /** * accumulate accumulates given value to current, and get returns current value */ public void testAccumulateAndGet() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - ai.accumulate(2.0); - assertEquals(2.0, ai.get()); - ai.accumulate(-4.0); - assertEquals(2.0, ai.get()); - ai.accumulate(4.0); - assertEquals(4.0, ai.get()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + acc.accumulate(2.0); + assertEquals(2.0, acc.get()); + acc.accumulate(-4.0); + assertEquals(2.0, acc.get()); + acc.accumulate(4.0); + assertEquals(4.0, acc.get()); } /** - * reset zeroes get + * reset() causes subsequent get() to return zero */ public void testReset() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - ai.accumulate(2.0); - assertEquals(2.0, ai.get()); - ai.reset(); - assertEquals(0.0, ai.get()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + acc.accumulate(2.0); + assertEquals(2.0, acc.get()); + acc.reset(); + assertEquals(0.0, acc.get()); } /** - * getThenReset returns get then zeros + * getThenReset() returns current value; subsequent get() returns zero */ public void testGetThenReset() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - ai.accumulate(2.0); - assertEquals(2.0, ai.get()); - assertEquals(2.0, ai.getThenReset()); - assertEquals(0.0, ai.get()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + acc.accumulate(2.0); + assertEquals(2.0, acc.get()); + assertEquals(2.0, acc.getThenReset()); + assertEquals(0.0, acc.get()); } /** * toString returns current value. */ public void testToString() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals("0.0", ai.toString()); - ai.accumulate(1.0); - assertEquals(Double.toString(1.0), ai.toString()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + assertEquals("0.0", acc.toString()); + acc.accumulate(1.0); + assertEquals(Double.toString(1.0), acc.toString()); } /** * intValue returns current value. */ public void testIntValue() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals(0, ai.intValue()); - ai.accumulate(1.0); - assertEquals(1, ai.intValue()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0, acc.intValue()); + acc.accumulate(1.0); + assertEquals(1, acc.intValue()); } /** * longValue returns current value. */ public void testLongValue() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals(0, ai.longValue()); - ai.accumulate(1.0); - assertEquals(1, ai.longValue()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0, acc.longValue()); + acc.accumulate(1.0); + assertEquals(1, acc.longValue()); } /** * floatValue returns current value. */ public void testFloatValue() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals(0.0f, ai.floatValue()); - ai.accumulate(1.0); - assertEquals(1.0f, ai.floatValue()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0.0f, acc.floatValue()); + acc.accumulate(1.0); + assertEquals(1.0f, acc.floatValue()); } /** * doubleValue returns current value. */ public void testDoubleValue() { - DoubleAccumulator ai = new DoubleAccumulator(Double::max, 0.0); - assertEquals(0.0, ai.doubleValue()); - ai.accumulate(1.0); - assertEquals(1.0, ai.doubleValue()); + DoubleAccumulator acc = new DoubleAccumulator(Double::max, 0.0); + assertEquals(0.0, acc.doubleValue()); + acc.accumulate(1.0); + assertEquals(1.0, acc.doubleValue()); } /** * accumulates by multiple threads produce correct result */ public void testAccumulateAndGetMT() { - final int incs = 1000000; - final int nthreads = 4; - final ExecutorService pool = Executors.newCachedThreadPool(); - DoubleAccumulator a = new DoubleAccumulator(Double::max, 0.0); - Phaser phaser = new Phaser(nthreads + 1); - for (int i = 0; i < nthreads; ++i) - pool.execute(new AccTask(a, phaser, incs)); - phaser.arriveAndAwaitAdvance(); - phaser.arriveAndAwaitAdvance(); - double expected = incs - 1; - double result = a.get(); - assertEquals(expected, result); - pool.shutdown(); - } - - static final class AccTask implements Runnable { - final DoubleAccumulator acc; - final Phaser phaser; - final int incs; - volatile double result; - AccTask(DoubleAccumulator acc, Phaser phaser, int incs) { - this.acc = acc; - this.phaser = phaser; - this.incs = incs; - } - - public void run() { + final DoubleAccumulator acc + = new DoubleAccumulator((x, y) -> x + y, 0.0); + final int nThreads = ThreadLocalRandom.current().nextInt(1, 5); + final Phaser phaser = new Phaser(nThreads + 1); + final int incs = expensiveTests ? 1_000_000 : 100_000; + final double total = nThreads * incs/2.0 * (incs - 1); // Gauss + final Runnable task = () -> { phaser.arriveAndAwaitAdvance(); - DoubleAccumulator a = acc; - for (int i = 0; i < incs; ++i) - a.accumulate(i); - result = a.get(); + for (int i = 0; i < incs; i++) { + acc.accumulate((double) i); + assertTrue(acc.get() <= total); + } phaser.arrive(); + }; + final ExecutorService p = Executors.newCachedThreadPool(); + try (PoolCleaner cleaner = cleaner(p)) { + for (int i = nThreads; i-->0; ) + p.execute(task); + phaser.arriveAndAwaitAdvance(); + phaser.arriveAndAwaitAdvance(); + assertEquals(total, acc.get()); } }