--- jsr166/src/test/tck/ScheduledExecutorTest.java 2015/10/04 08:07:31 1.62 +++ jsr166/src/test/tck/ScheduledExecutorTest.java 2017/03/26 02:00:39 1.88 @@ -7,6 +7,7 @@ */ import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import java.util.ArrayList; @@ -17,15 +18,17 @@ import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import junit.framework.Test; import junit.framework.TestSuite; @@ -42,13 +45,13 @@ public class ScheduledExecutorTest exten * execute successfully executes a runnable */ public void testExecute() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { final CountDownLatch done = new CountDownLatch(1); final Runnable task = new CheckedRunnable() { public void realRun() { done.countDown(); }}; p.execute(task); - assertTrue(done.await(SMALL_DELAY_MS, MILLISECONDS)); + await(done); } } @@ -56,7 +59,7 @@ public class ScheduledExecutorTest exten * delayed schedule of callable successfully executes after delay */ public void testSchedule1() throws Exception { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { final long startTime = System.nanoTime(); final CountDownLatch done = new CountDownLatch(1); @@ -77,7 +80,7 @@ public class ScheduledExecutorTest exten * delayed schedule of runnable successfully executes after delay */ public void testSchedule3() throws Exception { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { final long startTime = System.nanoTime(); final CountDownLatch done = new CountDownLatch(1); @@ -97,7 +100,7 @@ public class ScheduledExecutorTest exten * scheduleAtFixedRate executes runnable after given initial delay */ public void testSchedule4() throws Exception { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { final long startTime = System.nanoTime(); final CountDownLatch done = new CountDownLatch(1); @@ -119,7 +122,7 @@ public class ScheduledExecutorTest exten * scheduleWithFixedDelay executes runnable after given initial delay */ public void testSchedule5() throws Exception { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { final long startTime = System.nanoTime(); final CountDownLatch done = new CountDownLatch(1); @@ -143,54 +146,77 @@ public class ScheduledExecutorTest exten } /** - * scheduleAtFixedRate executes series of tasks at given rate + * scheduleAtFixedRate executes series of tasks at given rate. + * Eventually, it must hold that: + * cycles - 1 <= elapsedMillis/delay < cycles */ public void testFixedRateSequence() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { - long startTime = System.nanoTime(); - int cycles = 10; + final long startTime = System.nanoTime(); + final int cycles = 8; final CountDownLatch done = new CountDownLatch(cycles); - Runnable task = new CheckedRunnable() { + final Runnable task = new CheckedRunnable() { public void realRun() { done.countDown(); }}; - ScheduledFuture h = + final ScheduledFuture periodicTask = p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS); - done.await(); - h.cancel(true); - double normalizedTime = - (double) millisElapsedSince(startTime) / delay; - if (normalizedTime >= cycles - 1 && - normalizedTime <= cycles) + final int totalDelayMillis = (cycles - 1) * delay; + await(done, totalDelayMillis + LONG_DELAY_MS); + periodicTask.cancel(true); + final long elapsedMillis = millisElapsedSince(startTime); + assertTrue(elapsedMillis >= totalDelayMillis); + if (elapsedMillis <= cycles * delay) return; + // else retry with longer delay } - throw new AssertionError("unexpected execution rate"); + fail("unexpected execution rate"); } } /** - * scheduleWithFixedDelay executes series of tasks with given period + * scheduleWithFixedDelay executes series of tasks with given period. + * Eventually, it must hold that each task starts at least delay and at + * most 2 * delay after the termination of the previous task. */ public void testFixedDelaySequence() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) { - long startTime = System.nanoTime(); - int cycles = 10; + final long startTime = System.nanoTime(); + final AtomicLong previous = new AtomicLong(startTime); + final AtomicBoolean tryLongerDelay = new AtomicBoolean(false); + final int cycles = 8; final CountDownLatch done = new CountDownLatch(cycles); - Runnable task = new CheckedRunnable() { - public void realRun() { done.countDown(); }}; - ScheduledFuture h = + final int d = delay; + final Runnable task = new CheckedRunnable() { + public void realRun() { + long now = System.nanoTime(); + long elapsedMillis + = NANOSECONDS.toMillis(now - previous.get()); + if (done.getCount() == cycles) { // first execution + if (elapsedMillis >= d) + tryLongerDelay.set(true); + } else { + assertTrue(elapsedMillis >= d); + if (elapsedMillis >= 2 * d) + tryLongerDelay.set(true); + } + previous.set(now); + done.countDown(); + }}; + final ScheduledFuture periodicTask = p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS); - done.await(); - h.cancel(true); - double normalizedTime = - (double) millisElapsedSince(startTime) / delay; - if (normalizedTime >= cycles - 1 && - normalizedTime <= cycles) + final int totalDelayMillis = (cycles - 1) * delay; + await(done, totalDelayMillis + cycles * LONG_DELAY_MS); + periodicTask.cancel(true); + final long elapsedMillis = millisElapsedSince(startTime); + assertTrue(elapsedMillis >= totalDelayMillis); + if (!tryLongerDelay.get()) return; + // else retry with longer delay } - throw new AssertionError("unexpected execution rate"); + fail("unexpected execution rate"); } } @@ -198,7 +224,7 @@ public class ScheduledExecutorTest exten * execute(null) throws NPE */ public void testExecuteNull() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.execute(null); @@ -225,7 +251,7 @@ public class ScheduledExecutorTest exten * execute throws RejectedExecutionException if shutdown */ public void testSchedule1_RejectedExecutionException() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.shutdown(); @@ -241,7 +267,7 @@ public class ScheduledExecutorTest exten * schedule throws RejectedExecutionException if shutdown */ public void testSchedule2_RejectedExecutionException() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.shutdown(); @@ -257,7 +283,7 @@ public class ScheduledExecutorTest exten * schedule callable throws RejectedExecutionException if shutdown */ public void testSchedule3_RejectedExecutionException() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.shutdown(); @@ -273,7 +299,7 @@ public class ScheduledExecutorTest exten * scheduleAtFixedRate throws RejectedExecutionException if shutdown */ public void testScheduleAtFixedRate1_RejectedExecutionException() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.shutdown(); @@ -289,7 +315,7 @@ public class ScheduledExecutorTest exten * scheduleWithFixedDelay throws RejectedExecutionException if shutdown */ public void testScheduleWithFixedDelay1_RejectedExecutionException() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.shutdown(); @@ -306,20 +332,19 @@ public class ScheduledExecutorTest exten * thread becomes active */ public void testGetActiveCount() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(2); - try (PoolCleaner cleaner = cleaner(p)) { + try (PoolCleaner cleaner = cleaner(p, done)) { final CountDownLatch threadStarted = new CountDownLatch(1); - final CountDownLatch done = new CountDownLatch(1); assertEquals(0, p.getActiveCount()); p.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadStarted.countDown(); assertEquals(1, p.getActiveCount()); - done.await(); + await(done); }}); - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); assertEquals(1, p.getActiveCount()); - done.countDown(); } } @@ -338,13 +363,13 @@ public class ScheduledExecutorTest exten public void realRun() throws InterruptedException { threadStarted.countDown(); assertEquals(0, p.getCompletedTaskCount()); - threadProceed.await(); + await(threadProceed); threadDone.countDown(); }}); await(threadStarted); assertEquals(0, p.getCompletedTaskCount()); threadProceed.countDown(); - threadDone.await(); + await(threadDone); long startTime = System.nanoTime(); while (p.getCompletedTaskCount() != 1) { if (millisElapsedSince(startTime) > LONG_DELAY_MS) @@ -373,18 +398,17 @@ public class ScheduledExecutorTest exten final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(THREADS); final CountDownLatch threadsStarted = new CountDownLatch(THREADS); final CountDownLatch done = new CountDownLatch(1); - try (PoolCleaner cleaner = cleaner(p)) { + try (PoolCleaner cleaner = cleaner(p, done)) { assertEquals(0, p.getLargestPoolSize()); for (int i = 0; i < THREADS; i++) p.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadsStarted.countDown(); - done.await(); + await(done); assertEquals(THREADS, p.getLargestPoolSize()); }}); - assertTrue(threadsStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadsStarted); assertEquals(THREADS, p.getLargestPoolSize()); - done.countDown(); } assertEquals(THREADS, p.getLargestPoolSize()); } @@ -397,17 +421,16 @@ public class ScheduledExecutorTest exten final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); final CountDownLatch threadStarted = new CountDownLatch(1); final CountDownLatch done = new CountDownLatch(1); - try (PoolCleaner cleaner = cleaner(p)) { + try (PoolCleaner cleaner = cleaner(p, done)) { assertEquals(0, p.getPoolSize()); p.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadStarted.countDown(); assertEquals(1, p.getPoolSize()); - done.await(); + await(done); }}); - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); assertEquals(1, p.getPoolSize()); - done.countDown(); } } @@ -416,32 +439,47 @@ public class ScheduledExecutorTest exten * submitted */ public void testGetTaskCount() throws InterruptedException { + final int TASKS = 3; + final CountDownLatch done = new CountDownLatch(1); final ThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); - try (PoolCleaner cleaner = cleaner(p)) { + try (PoolCleaner cleaner = cleaner(p, done)) { final CountDownLatch threadStarted = new CountDownLatch(1); - final CountDownLatch done = new CountDownLatch(1); - final int TASKS = 5; assertEquals(0, p.getTaskCount()); - for (int i = 0; i < TASKS; i++) + assertEquals(0, p.getCompletedTaskCount()); + p.execute(new CheckedRunnable() { + public void realRun() throws InterruptedException { + threadStarted.countDown(); + await(done); + }}); + await(threadStarted); + assertEquals(1, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); + for (int i = 0; i < TASKS; i++) { + assertEquals(1 + i, p.getTaskCount()); p.execute(new CheckedRunnable() { public void realRun() throws InterruptedException { threadStarted.countDown(); - done.await(); + assertEquals(1 + TASKS, p.getTaskCount()); + await(done); }}); - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); - assertEquals(TASKS, p.getTaskCount()); - done.countDown(); + } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(0, p.getCompletedTaskCount()); } + assertEquals(1 + TASKS, p.getTaskCount()); + assertEquals(1 + TASKS, p.getCompletedTaskCount()); } /** * getThreadFactory returns factory in constructor if not set */ public void testGetThreadFactory() throws InterruptedException { - ThreadFactory threadFactory = new SimpleThreadFactory(); - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1, threadFactory); - assertSame(threadFactory, p.getThreadFactory()); - joinPool(p); + final ThreadFactory threadFactory = new SimpleThreadFactory(); + final ScheduledThreadPoolExecutor p = + new ScheduledThreadPoolExecutor(1, threadFactory); + try (PoolCleaner cleaner = cleaner(p)) { + assertSame(threadFactory, p.getThreadFactory()); + } } /** @@ -449,7 +487,7 @@ public class ScheduledExecutorTest exten */ public void testSetThreadFactory() throws InterruptedException { ThreadFactory threadFactory = new SimpleThreadFactory(); - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { p.setThreadFactory(threadFactory); assertSame(threadFactory, p.getThreadFactory()); @@ -460,7 +498,7 @@ public class ScheduledExecutorTest exten * setThreadFactory(null) throws NPE */ public void testSetThreadFactoryNull() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); try (PoolCleaner cleaner = cleaner(p)) { try { p.setThreadFactory(null); @@ -470,18 +508,28 @@ public class ScheduledExecutorTest exten } /** + * The default rejected execution handler is AbortPolicy. + */ + public void testDefaultRejectedExecutionHandler() { + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + assertTrue(p.getRejectedExecutionHandler() + instanceof ThreadPoolExecutor.AbortPolicy); + } + } + + /** * isShutdown is false before shutdown, true after */ public void testIsShutdown() { - - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); - try { - assertFalse(p.isShutdown()); - } - finally { - try { p.shutdown(); } catch (SecurityException ok) { return; } + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + assertFalse(p.isShutdown()); + try (PoolCleaner cleaner = cleaner(p)) { + try { + p.shutdown(); + assertTrue(p.isShutdown()); + } catch (SecurityException ok) {} } - assertTrue(p.isShutdown()); } /** @@ -497,9 +545,9 @@ public class ScheduledExecutorTest exten public void realRun() throws InterruptedException { assertFalse(p.isTerminated()); threadStarted.countDown(); - done.await(); + await(done); }}); - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); assertFalse(p.isTerminating()); done.countDown(); try { p.shutdown(); } catch (SecurityException ok) { return; } @@ -521,9 +569,9 @@ public class ScheduledExecutorTest exten public void realRun() throws InterruptedException { assertFalse(p.isTerminating()); threadStarted.countDown(); - done.await(); + await(done); }}); - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); assertFalse(p.isTerminating()); done.countDown(); try { p.shutdown(); } catch (SecurityException ok) { return; } @@ -537,24 +585,23 @@ public class ScheduledExecutorTest exten * getQueue returns the work queue, which contains queued tasks */ public void testGetQueue() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); - try (PoolCleaner cleaner = cleaner(p)) { + final CountDownLatch done = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, done)) { final CountDownLatch threadStarted = new CountDownLatch(1); - final CountDownLatch done = new CountDownLatch(1); ScheduledFuture[] tasks = new ScheduledFuture[5]; for (int i = 0; i < tasks.length; i++) { Runnable r = new CheckedRunnable() { public void realRun() throws InterruptedException { threadStarted.countDown(); - done.await(); + await(done); }}; tasks[i] = p.schedule(r, 1, MILLISECONDS); } - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); BlockingQueue q = p.getQueue(); assertTrue(q.contains(tasks[tasks.length - 1])); assertFalse(q.contains(tasks[0])); - done.countDown(); } } @@ -562,20 +609,20 @@ public class ScheduledExecutorTest exten * remove(task) removes queued task, and fails to remove active task */ public void testRemove() throws InterruptedException { + final CountDownLatch done = new CountDownLatch(1); final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); - try (PoolCleaner cleaner = cleaner(p)) { + try (PoolCleaner cleaner = cleaner(p, done)) { ScheduledFuture[] tasks = new ScheduledFuture[5]; final CountDownLatch threadStarted = new CountDownLatch(1); - final CountDownLatch done = new CountDownLatch(1); for (int i = 0; i < tasks.length; i++) { Runnable r = new CheckedRunnable() { public void realRun() throws InterruptedException { threadStarted.countDown(); - done.await(); + await(done); }}; tasks[i] = p.schedule(r, 1, MILLISECONDS); } - assertTrue(threadStarted.await(MEDIUM_DELAY_MS, MILLISECONDS)); + await(threadStarted); BlockingQueue q = p.getQueue(); assertFalse(p.remove((Runnable)tasks[0])); assertTrue(q.contains((Runnable)tasks[4])); @@ -586,7 +633,6 @@ public class ScheduledExecutorTest exten assertTrue(q.contains((Runnable)tasks[3])); assertTrue(p.remove((Runnable)tasks[3])); assertFalse(q.contains((Runnable)tasks[3])); - done.countDown(); } } @@ -594,12 +640,15 @@ public class ScheduledExecutorTest exten * purge eventually removes cancelled tasks from the queue */ public void testPurge() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); - ScheduledFuture[] tasks = new ScheduledFuture[5]; - for (int i = 0; i < tasks.length; i++) - tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(), - LONG_DELAY_MS, MILLISECONDS); - try { + final ScheduledFuture[] tasks = new ScheduledFuture[5]; + final Runnable releaser = new Runnable() { public void run() { + for (ScheduledFuture task : tasks) + if (task != null) task.cancel(true); }}; + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p, releaser)) { + for (int i = 0; i < tasks.length; i++) + tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(), + LONG_DELAY_MS, MILLISECONDS); int max = tasks.length; if (tasks[4].cancel(true)) --max; if (tasks[3].cancel(true)) --max; @@ -611,12 +660,8 @@ public class ScheduledExecutorTest exten long count = p.getTaskCount(); if (count == max) return; - } while (millisElapsedSince(startTime) < MEDIUM_DELAY_MS); + } while (millisElapsedSince(startTime) < LONG_DELAY_MS); fail("Purge failed to remove cancelled tasks"); - } finally { - for (ScheduledFuture task : tasks) - task.cancel(true); - joinPool(p); } } @@ -630,7 +675,7 @@ public class ScheduledExecutorTest exten final AtomicInteger ran = new AtomicInteger(0); final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(poolSize); - CountDownLatch threadsStarted = new CountDownLatch(poolSize); + final CountDownLatch threadsStarted = new CountDownLatch(poolSize); Runnable waiter = new CheckedRunnable() { public void realRun() { threadsStarted.countDown(); try { @@ -640,7 +685,7 @@ public class ScheduledExecutorTest exten }}; for (int i = 0; i < count; i++) p.execute(waiter); - assertTrue(threadsStarted.await(LONG_DELAY_MS, MILLISECONDS)); + await(threadsStarted); assertEquals(poolSize, p.getActiveCount()); assertEquals(0, p.getCompletedTaskCount()); final List queuedTasks; @@ -663,7 +708,7 @@ public class ScheduledExecutorTest exten * and those tasks are drained from the queue */ public void testShutdownNow_delayedTasks() throws InterruptedException { - ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); List tasks = new ArrayList<>(); for (int i = 0; i < 3; i++) { Runnable r = new NoOpRunnable(); @@ -700,26 +745,38 @@ public class ScheduledExecutorTest exten * - setContinueExistingPeriodicTasksAfterShutdownPolicy */ public void testShutdown_cancellation() throws Exception { - Boolean[] allBooleans = { null, Boolean.FALSE, Boolean.TRUE }; - for (Boolean policy : allBooleans) - { final int poolSize = 2; final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(poolSize); - final boolean effectiveDelayedPolicy = (policy != Boolean.FALSE); - final boolean effectivePeriodicPolicy = (policy == Boolean.TRUE); - final boolean effectiveRemovePolicy = (policy == Boolean.TRUE); - if (policy != null) { - p.setExecuteExistingDelayedTasksAfterShutdownPolicy(policy); - p.setContinueExistingPeriodicTasksAfterShutdownPolicy(policy); - p.setRemoveOnCancelPolicy(policy); - } + final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final boolean effectiveDelayedPolicy; + final boolean effectivePeriodicPolicy; + final boolean effectiveRemovePolicy; + + if (rnd.nextBoolean()) + p.setExecuteExistingDelayedTasksAfterShutdownPolicy( + effectiveDelayedPolicy = rnd.nextBoolean()); + else + effectiveDelayedPolicy = true; assertEquals(effectiveDelayedPolicy, p.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + + if (rnd.nextBoolean()) + p.setContinueExistingPeriodicTasksAfterShutdownPolicy( + effectivePeriodicPolicy = rnd.nextBoolean()); + else + effectivePeriodicPolicy = false; assertEquals(effectivePeriodicPolicy, p.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + + if (rnd.nextBoolean()) + p.setRemoveOnCancelPolicy( + effectiveRemovePolicy = rnd.nextBoolean()); + else + effectiveRemovePolicy = false; assertEquals(effectiveRemovePolicy, p.getRemoveOnCancelPolicy()); + // Strategy: Wedge the pool with poolSize "blocker" threads final AtomicInteger ran = new AtomicInteger(0); final CountDownLatch poolBlocked = new CountDownLatch(poolSize); @@ -729,7 +786,7 @@ public class ScheduledExecutorTest exten Runnable task = new CheckedRunnable() { public void realRun() throws InterruptedException { poolBlocked.countDown(); - assertTrue(unblock.await(LONG_DELAY_MS, MILLISECONDS)); + await(unblock); ran.getAndIncrement(); }}; List> blockers = new ArrayList<>(); @@ -737,12 +794,12 @@ public class ScheduledExecutorTest exten List> delayeds = new ArrayList<>(); for (int i = 0; i < poolSize; i++) blockers.add(p.submit(task)); - assertTrue(poolBlocked.await(LONG_DELAY_MS, MILLISECONDS)); + await(poolBlocked); - periodics.add(p.scheduleAtFixedRate(countDowner(periodicLatch1), - 1, 1, MILLISECONDS)); - periodics.add(p.scheduleWithFixedDelay(countDowner(periodicLatch2), - 1, 1, MILLISECONDS)); + periodics.add(p.scheduleAtFixedRate( + countDowner(periodicLatch1), 1, 1, MILLISECONDS)); + periodics.add(p.scheduleWithFixedDelay( + countDowner(periodicLatch2), 1, 1, MILLISECONDS)); delayeds.add(p.schedule(task, 1, MILLISECONDS)); assertTrue(p.getQueue().containsAll(periodics)); @@ -764,27 +821,33 @@ public class ScheduledExecutorTest exten assertEquals(effectiveDelayedPolicy, p.getQueue().containsAll(delayeds)); } - // Release all pool threads - unblock.countDown(); + unblock.countDown(); // Release all pool threads - for (Future delayed : delayeds) { - if (effectiveDelayedPolicy) { - assertNull(delayed.get()); - } - } + if (effectiveDelayedPolicy) + for (Future delayed : delayeds) assertNull(delayed.get()); if (effectivePeriodicPolicy) { - assertTrue(periodicLatch1.await(LONG_DELAY_MS, MILLISECONDS)); - assertTrue(periodicLatch2.await(LONG_DELAY_MS, MILLISECONDS)); + await(periodicLatch1); + await(periodicLatch2); for (Future periodic : periodics) { assertTrue(periodic.cancel(false)); assertTrue(periodic.isCancelled()); assertTrue(periodic.isDone()); } } + for (Future blocker : blockers) assertNull(blocker.get()); assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); assertTrue(p.isTerminated()); + + for (Future future : delayeds) { + assertTrue(effectiveDelayedPolicy ^ future.isCancelled()); + assertTrue(future.isDone()); + } + for (Future future : periodics) + assertTrue(future.isCancelled()); + for (Future future : blockers) + assertNull(future.get()); assertEquals(2 + (effectiveDelayedPolicy ? 1 : 0), ran.get()); - }} + } /** * completed submit of callable returns result @@ -855,7 +918,7 @@ public class ScheduledExecutorTest exten CountDownLatch latch = new CountDownLatch(1); final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(latchAwaitingStringTask(latch)); l.add(null); try { @@ -872,7 +935,7 @@ public class ScheduledExecutorTest exten public void testInvokeAny4() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new NPETask()); try { e.invokeAny(l); @@ -889,7 +952,7 @@ public class ScheduledExecutorTest exten public void testInvokeAny5() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(new StringTask()); String result = e.invokeAny(l); @@ -927,7 +990,7 @@ public class ScheduledExecutorTest exten public void testInvokeAll3() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(null); try { @@ -943,7 +1006,7 @@ public class ScheduledExecutorTest exten public void testInvokeAll4() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new NPETask()); List> futures = e.invokeAll(l); assertEquals(1, futures.size()); @@ -962,7 +1025,7 @@ public class ScheduledExecutorTest exten public void testInvokeAll5() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(new StringTask()); List> futures = e.invokeAll(l); @@ -991,7 +1054,7 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAnyNullTimeUnit() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); try { e.invokeAny(l, MEDIUM_DELAY_MS, null); @@ -1020,7 +1083,7 @@ public class ScheduledExecutorTest exten CountDownLatch latch = new CountDownLatch(1); final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(latchAwaitingStringTask(latch)); l.add(null); try { @@ -1037,14 +1100,16 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAny4() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + long startTime = System.nanoTime(); + List> l = new ArrayList<>(); l.add(new NPETask()); try { - e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); shouldThrow(); } catch (ExecutionException success) { assertTrue(success.getCause() instanceof NullPointerException); } + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); } } @@ -1054,11 +1119,13 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAny5() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + long startTime = System.nanoTime(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(new StringTask()); - String result = e.invokeAny(l, MEDIUM_DELAY_MS, MILLISECONDS); + String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS); assertSame(TEST_STRING, result); + assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS); } } @@ -1081,7 +1148,7 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAllNullTimeUnit() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); try { e.invokeAll(l, MEDIUM_DELAY_MS, null); @@ -1108,7 +1175,7 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAll3() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(null); try { @@ -1124,10 +1191,10 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAll4() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new NPETask()); List> futures = - e.invokeAll(l, MEDIUM_DELAY_MS, MILLISECONDS); + e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS); assertEquals(1, futures.size()); try { futures.get(0).get(); @@ -1144,7 +1211,7 @@ public class ScheduledExecutorTest exten public void testTimedInvokeAll5() throws Exception { final ExecutorService e = new ScheduledThreadPoolExecutor(2); try (PoolCleaner cleaner = cleaner(e)) { - List> l = new ArrayList>(); + List> l = new ArrayList<>(); l.add(new StringTask()); l.add(new StringTask()); List> futures = @@ -1159,16 +1226,22 @@ public class ScheduledExecutorTest exten * timed invokeAll(c) cancels tasks not completed by timeout */ public void testTimedInvokeAll6() throws Exception { - final ExecutorService e = new ScheduledThreadPoolExecutor(2); - try (PoolCleaner cleaner = cleaner(e)) { - for (long timeout = timeoutMillis();;) { + for (long timeout = timeoutMillis();;) { + final CountDownLatch done = new CountDownLatch(1); + final Callable waiter = new CheckedCallable() { + public String realCall() { + try { done.await(LONG_DELAY_MS, MILLISECONDS); } + catch (InterruptedException ok) {} + return "1"; }}; + final ExecutorService p = new ScheduledThreadPoolExecutor(2); + try (PoolCleaner cleaner = cleaner(p, done)) { List> tasks = new ArrayList<>(); tasks.add(new StringTask("0")); - tasks.add(Executors.callable(new LongPossiblyInterruptedRunnable(), TEST_STRING)); + tasks.add(waiter); tasks.add(new StringTask("2")); long startTime = System.nanoTime(); List> futures = - e.invokeAll(tasks, timeout, MILLISECONDS); + p.invokeAll(tasks, timeout, MILLISECONDS); assertEquals(tasks.size(), futures.size()); assertTrue(millisElapsedSince(startTime) >= timeout); for (Future future : futures) @@ -1187,4 +1260,27 @@ public class ScheduledExecutorTest exten } } + /** + * A fixed delay task with overflowing period should not prevent a + * one-shot task from executing. + * https://bugs.openjdk.java.net/browse/JDK-8051859 + */ + public void testScheduleWithFixedDelay_overflow() throws Exception { + final CountDownLatch delayedDone = new CountDownLatch(1); + final CountDownLatch immediateDone = new CountDownLatch(1); + final ScheduledThreadPoolExecutor p = new ScheduledThreadPoolExecutor(1); + try (PoolCleaner cleaner = cleaner(p)) { + final Runnable immediate = new Runnable() { public void run() { + immediateDone.countDown(); + }}; + final Runnable delayed = new Runnable() { public void run() { + delayedDone.countDown(); + p.submit(immediate); + }}; + p.scheduleWithFixedDelay(delayed, 0L, Long.MAX_VALUE, SECONDS); + await(delayedDone); + await(immediateDone); + } + } + }