ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/tck/ScheduledExecutorSubclassTest.java
(Generate patch)

Comparing jsr166/src/test/tck/ScheduledExecutorSubclassTest.java (file contents):
Revision 1.2 by jsr166, Mon Nov 2 20:28:31 2009 UTC vs.
Revision 1.68 by jsr166, Mon May 29 22:44:27 2017 UTC

# Line 1 | Line 1
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/licenses/publicdomain
4 > * http://creativecommons.org/publicdomain/zero/1.0/
5   */
6  
7 < import junit.framework.*;
8 < import java.util.*;
9 < import java.util.concurrent.*;
10 < import java.util.concurrent.atomic.*;
7 > import static java.util.concurrent.TimeUnit.MILLISECONDS;
8 > import static java.util.concurrent.TimeUnit.NANOSECONDS;
9 > import static java.util.concurrent.TimeUnit.SECONDS;
10 >
11 > import java.util.ArrayList;
12 > import java.util.Collection;
13 > import java.util.Collections;
14 > import java.util.HashSet;
15 > import java.util.List;
16 > import java.util.concurrent.BlockingQueue;
17 > import java.util.concurrent.Callable;
18 > import java.util.concurrent.CancellationException;
19 > import java.util.concurrent.CountDownLatch;
20 > import java.util.concurrent.Delayed;
21 > import java.util.concurrent.ExecutionException;
22 > import java.util.concurrent.ExecutorService;
23 > import java.util.concurrent.Future;
24 > import java.util.concurrent.RejectedExecutionException;
25 > import java.util.concurrent.RejectedExecutionHandler;
26 > import java.util.concurrent.RunnableScheduledFuture;
27 > import java.util.concurrent.ScheduledFuture;
28 > import java.util.concurrent.ScheduledThreadPoolExecutor;
29 > import java.util.concurrent.ThreadFactory;
30 > import java.util.concurrent.ThreadLocalRandom;
31 > import java.util.concurrent.ThreadPoolExecutor;
32 > import java.util.concurrent.TimeoutException;
33 > import java.util.concurrent.TimeUnit;
34 > import java.util.concurrent.atomic.AtomicBoolean;
35 > import java.util.concurrent.atomic.AtomicInteger;
36 > import java.util.concurrent.atomic.AtomicLong;
37 > import java.util.stream.Stream;
38 >
39 > import junit.framework.Test;
40 > import junit.framework.TestSuite;
41  
42   public class ScheduledExecutorSubclassTest extends JSR166TestCase {
43      public static void main(String[] args) {
44 <        junit.textui.TestRunner.run (suite());
44 >        main(suite(), args);
45      }
46      public static Test suite() {
47 <        return new TestSuite(ScheduledExecutorTest.class);
47 >        return new TestSuite(ScheduledExecutorSubclassTest.class);
48      }
49  
50      static class CustomTask<V> implements RunnableScheduledFuture<V> {
51 <        RunnableScheduledFuture<V> task;
51 >        private final RunnableScheduledFuture<V> task;
52          volatile boolean ran;
53 <        CustomTask(RunnableScheduledFuture<V> t) { task = t; }
53 >        CustomTask(RunnableScheduledFuture<V> task) { this.task = task; }
54          public boolean isPeriodic() { return task.isPeriodic(); }
55          public void run() {
56              ran = true;
# Line 35 | Line 65 | public class ScheduledExecutorSubclassTe
65          }
66          public boolean isCancelled() { return task.isCancelled(); }
67          public boolean isDone() { return task.isDone(); }
68 <        public V get() throws InterruptedException,  ExecutionException {
68 >        public V get() throws InterruptedException, ExecutionException {
69              V v = task.get();
70              assertTrue(ran);
71              return v;
72          }
73 <        public V get(long time, TimeUnit unit) throws InterruptedException,  ExecutionException, TimeoutException {
73 >        public V get(long time, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
74              V v = task.get(time, unit);
75              assertTrue(ran);
76              return v;
77          }
78      }
79  
50
80      public class CustomExecutor extends ScheduledThreadPoolExecutor {
81  
82          protected <V> RunnableScheduledFuture<V> decorateTask(Runnable r, RunnableScheduledFuture<V> task) {
# Line 57 | Line 86 | public class ScheduledExecutorSubclassTe
86          protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> c, RunnableScheduledFuture<V> task) {
87              return new CustomTask<V>(task);
88          }
89 <        CustomExecutor(int corePoolSize) { super(corePoolSize);}
89 >        CustomExecutor(int corePoolSize) { super(corePoolSize); }
90          CustomExecutor(int corePoolSize, RejectedExecutionHandler handler) {
91              super(corePoolSize, handler);
92          }
# Line 72 | Line 101 | public class ScheduledExecutorSubclassTe
101  
102      }
103  
75
76
104      /**
105       * execute successfully executes a runnable
106       */
107 <    public void testExecute() {
108 <        try {
109 <            TrackedShortRunnable runnable =new TrackedShortRunnable();
110 <            CustomExecutor p1 = new CustomExecutor(1);
111 <            p1.execute(runnable);
112 <            assertFalse(runnable.done);
113 <            Thread.sleep(SHORT_DELAY_MS);
114 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
88 <            try {
89 <                Thread.sleep(MEDIUM_DELAY_MS);
90 <            } catch(InterruptedException e){
91 <                unexpectedException();
92 <            }
93 <            assertTrue(runnable.done);
94 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
95 <            joinPool(p1);
96 <        }
97 <        catch(Exception e){
98 <            unexpectedException();
107 >    public void testExecute() throws InterruptedException {
108 >        final CustomExecutor p = new CustomExecutor(1);
109 >        try (PoolCleaner cleaner = cleaner(p)) {
110 >            final CountDownLatch done = new CountDownLatch(1);
111 >            final Runnable task = new CheckedRunnable() {
112 >                public void realRun() { done.countDown(); }};
113 >            p.execute(task);
114 >            await(done);
115          }
100
116      }
117  
103
118      /**
119       * delayed schedule of callable successfully executes after delay
120       */
121 <    public void testSchedule1() {
122 <        try {
123 <            TrackedCallable callable = new TrackedCallable();
124 <            CustomExecutor p1 = new CustomExecutor(1);
125 <            Future f = p1.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
126 <            assertFalse(callable.done);
127 <            Thread.sleep(MEDIUM_DELAY_MS);
128 <            assertTrue(callable.done);
129 <            assertEquals(Boolean.TRUE, f.get());
130 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
131 <            joinPool(p1);
132 <        } catch(RejectedExecutionException e){}
133 <        catch(Exception e){
134 <            e.printStackTrace();
121 <            unexpectedException();
121 >    public void testSchedule1() throws Exception {
122 >        final CountDownLatch done = new CountDownLatch(1);
123 >        final CustomExecutor p = new CustomExecutor(1);
124 >        try (PoolCleaner cleaner = cleaner(p, done)) {
125 >            final long startTime = System.nanoTime();
126 >            Callable task = new CheckedCallable<Boolean>() {
127 >                public Boolean realCall() {
128 >                    done.countDown();
129 >                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
130 >                    return Boolean.TRUE;
131 >                }};
132 >            Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
133 >            assertSame(Boolean.TRUE, f.get());
134 >            assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
135          }
136      }
137  
138      /**
139 <     *  delayed schedule of runnable successfully executes after delay
140 <     */
141 <    public void testSchedule3() {
142 <        try {
143 <            TrackedShortRunnable runnable = new TrackedShortRunnable();
144 <            CustomExecutor p1 = new CustomExecutor(1);
145 <            p1.schedule(runnable, SMALL_DELAY_MS, TimeUnit.MILLISECONDS);
146 <            Thread.sleep(SHORT_DELAY_MS);
147 <            assertFalse(runnable.done);
148 <            Thread.sleep(MEDIUM_DELAY_MS);
149 <            assertTrue(runnable.done);
150 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
151 <            joinPool(p1);
152 <        } catch(Exception e){
153 <            unexpectedException();
139 >     * delayed schedule of runnable successfully executes after delay
140 >     */
141 >    public void testSchedule3() throws Exception {
142 >        final CustomExecutor p = new CustomExecutor(1);
143 >        try (PoolCleaner cleaner = cleaner(p)) {
144 >            final long startTime = System.nanoTime();
145 >            final CountDownLatch done = new CountDownLatch(1);
146 >            Runnable task = new CheckedRunnable() {
147 >                public void realRun() {
148 >                    done.countDown();
149 >                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
150 >                }};
151 >            Future f = p.schedule(task, timeoutMillis(), MILLISECONDS);
152 >            await(done);
153 >            assertNull(f.get(LONG_DELAY_MS, MILLISECONDS));
154 >            assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
155          }
156      }
157  
158      /**
159       * scheduleAtFixedRate executes runnable after given initial delay
160       */
161 <    public void testSchedule4() {
162 <        try {
163 <            TrackedShortRunnable runnable = new TrackedShortRunnable();
164 <            CustomExecutor p1 = new CustomExecutor(1);
165 <            ScheduledFuture h = p1.scheduleAtFixedRate(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
166 <            assertFalse(runnable.done);
167 <            Thread.sleep(MEDIUM_DELAY_MS);
168 <            assertTrue(runnable.done);
169 <            h.cancel(true);
170 <            joinPool(p1);
171 <        } catch(Exception e){
172 <            unexpectedException();
161 >    public void testSchedule4() throws InterruptedException {
162 >        final CustomExecutor p = new CustomExecutor(1);
163 >        try (PoolCleaner cleaner = cleaner(p)) {
164 >            final long startTime = System.nanoTime();
165 >            final CountDownLatch done = new CountDownLatch(1);
166 >            Runnable task = new CheckedRunnable() {
167 >                public void realRun() {
168 >                    done.countDown();
169 >                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
170 >                }};
171 >            ScheduledFuture f =
172 >                p.scheduleAtFixedRate(task, timeoutMillis(),
173 >                                      LONG_DELAY_MS, MILLISECONDS);
174 >            await(done);
175 >            assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
176 >            f.cancel(true);
177          }
178      }
179  
162    static class RunnableCounter implements Runnable {
163        AtomicInteger count = new AtomicInteger(0);
164        public void run() { count.getAndIncrement(); }
165    }
166
180      /**
181       * scheduleWithFixedDelay executes runnable after given initial delay
182       */
183 <    public void testSchedule5() {
184 <        try {
185 <            TrackedShortRunnable runnable = new TrackedShortRunnable();
186 <            CustomExecutor p1 = new CustomExecutor(1);
187 <            ScheduledFuture h = p1.scheduleWithFixedDelay(runnable, SHORT_DELAY_MS, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
188 <            assertFalse(runnable.done);
189 <            Thread.sleep(MEDIUM_DELAY_MS);
190 <            assertTrue(runnable.done);
191 <            h.cancel(true);
192 <            joinPool(p1);
193 <        } catch(Exception e){
194 <            unexpectedException();
183 >    public void testSchedule5() throws InterruptedException {
184 >        final CustomExecutor p = new CustomExecutor(1);
185 >        try (PoolCleaner cleaner = cleaner(p)) {
186 >            final long startTime = System.nanoTime();
187 >            final CountDownLatch done = new CountDownLatch(1);
188 >            Runnable task = new CheckedRunnable() {
189 >                public void realRun() {
190 >                    done.countDown();
191 >                    assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
192 >                }};
193 >            ScheduledFuture f =
194 >                p.scheduleWithFixedDelay(task, timeoutMillis(),
195 >                                         LONG_DELAY_MS, MILLISECONDS);
196 >            await(done);
197 >            assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
198 >            f.cancel(true);
199          }
200      }
201  
202 +    static class RunnableCounter implements Runnable {
203 +        AtomicInteger count = new AtomicInteger(0);
204 +        public void run() { count.getAndIncrement(); }
205 +    }
206 +
207      /**
208 <     * scheduleAtFixedRate executes series of tasks at given rate
209 <     */
210 <    public void testFixedRateSequence() {
211 <        try {
212 <            CustomExecutor p1 = new CustomExecutor(1);
213 <            RunnableCounter counter = new RunnableCounter();
214 <            ScheduledFuture h =
215 <                p1.scheduleAtFixedRate(counter, 0, 1, TimeUnit.MILLISECONDS);
216 <            Thread.sleep(SMALL_DELAY_MS);
217 <            h.cancel(true);
218 <            int c = counter.count.get();
219 <            // By time scaling conventions, we must have at least
220 <            // an execution per SHORT delay, but no more than one SHORT more
221 <            assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
222 <            assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
223 <            joinPool(p1);
224 <        } catch(Exception e){
225 <            unexpectedException();
208 >     * scheduleAtFixedRate executes series of tasks at given rate.
209 >     * Eventually, it must hold that:
210 >     *   cycles - 1 <= elapsedMillis/delay < cycles
211 >     */
212 >    public void testFixedRateSequence() throws InterruptedException {
213 >        final CustomExecutor p = new CustomExecutor(1);
214 >        try (PoolCleaner cleaner = cleaner(p)) {
215 >            for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
216 >                final long startTime = System.nanoTime();
217 >                final int cycles = 8;
218 >                final CountDownLatch done = new CountDownLatch(cycles);
219 >                final Runnable task = new CheckedRunnable() {
220 >                    public void realRun() { done.countDown(); }};
221 >                final ScheduledFuture periodicTask =
222 >                    p.scheduleAtFixedRate(task, 0, delay, MILLISECONDS);
223 >                final int totalDelayMillis = (cycles - 1) * delay;
224 >                await(done, totalDelayMillis + LONG_DELAY_MS);
225 >                periodicTask.cancel(true);
226 >                final long elapsedMillis = millisElapsedSince(startTime);
227 >                assertTrue(elapsedMillis >= totalDelayMillis);
228 >                if (elapsedMillis <= cycles * delay)
229 >                    return;
230 >                // else retry with longer delay
231 >            }
232 >            fail("unexpected execution rate");
233          }
234      }
235  
236      /**
237 <     * scheduleWithFixedDelay executes series of tasks with given period
238 <     */
239 <    public void testFixedDelaySequence() {
240 <        try {
241 <            CustomExecutor p1 = new CustomExecutor(1);
242 <            RunnableCounter counter = new RunnableCounter();
243 <            ScheduledFuture h =
244 <                p1.scheduleWithFixedDelay(counter, 0, 1, TimeUnit.MILLISECONDS);
245 <            Thread.sleep(SMALL_DELAY_MS);
246 <            h.cancel(true);
247 <            int c = counter.count.get();
248 <            assertTrue(c >= SMALL_DELAY_MS / SHORT_DELAY_MS);
249 <            assertTrue(c <= SMALL_DELAY_MS + SHORT_DELAY_MS);
250 <            joinPool(p1);
251 <        } catch(Exception e){
252 <            unexpectedException();
237 >     * scheduleWithFixedDelay executes series of tasks with given period.
238 >     * Eventually, it must hold that each task starts at least delay and at
239 >     * most 2 * delay after the termination of the previous task.
240 >     */
241 >    public void testFixedDelaySequence() throws InterruptedException {
242 >        final CustomExecutor p = new CustomExecutor(1);
243 >        try (PoolCleaner cleaner = cleaner(p)) {
244 >            for (int delay = 1; delay <= LONG_DELAY_MS; delay *= 3) {
245 >                final long startTime = System.nanoTime();
246 >                final AtomicLong previous = new AtomicLong(startTime);
247 >                final AtomicBoolean tryLongerDelay = new AtomicBoolean(false);
248 >                final int cycles = 8;
249 >                final CountDownLatch done = new CountDownLatch(cycles);
250 >                final int d = delay;
251 >                final Runnable task = new CheckedRunnable() {
252 >                    public void realRun() {
253 >                        long now = System.nanoTime();
254 >                        long elapsedMillis
255 >                            = NANOSECONDS.toMillis(now - previous.get());
256 >                        if (done.getCount() == cycles) { // first execution
257 >                            if (elapsedMillis >= d)
258 >                                tryLongerDelay.set(true);
259 >                        } else {
260 >                            assertTrue(elapsedMillis >= d);
261 >                            if (elapsedMillis >= 2 * d)
262 >                                tryLongerDelay.set(true);
263 >                        }
264 >                        previous.set(now);
265 >                        done.countDown();
266 >                    }};
267 >                final ScheduledFuture periodicTask =
268 >                    p.scheduleWithFixedDelay(task, 0, delay, MILLISECONDS);
269 >                final int totalDelayMillis = (cycles - 1) * delay;
270 >                await(done, totalDelayMillis + cycles * LONG_DELAY_MS);
271 >                periodicTask.cancel(true);
272 >                final long elapsedMillis = millisElapsedSince(startTime);
273 >                assertTrue(elapsedMillis >= totalDelayMillis);
274 >                if (!tryLongerDelay.get())
275 >                    return;
276 >                // else retry with longer delay
277 >            }
278 >            fail("unexpected execution rate");
279          }
280      }
281  
227
282      /**
283 <     *  execute (null) throws NPE
283 >     * execute(null) throws NPE
284       */
285 <    public void testExecuteNull() {
286 <        CustomExecutor se = null;
287 <        try {
288 <            se = new CustomExecutor(1);
289 <            se.execute(null);
290 <            shouldThrow();
291 <        } catch(NullPointerException success){}
238 <        catch(Exception e){
239 <            unexpectedException();
285 >    public void testExecuteNull() throws InterruptedException {
286 >        final CustomExecutor p = new CustomExecutor(1);
287 >        try (PoolCleaner cleaner = cleaner(p)) {
288 >            try {
289 >                p.execute(null);
290 >                shouldThrow();
291 >            } catch (NullPointerException success) {}
292          }
241
242        joinPool(se);
293      }
294  
295      /**
296 <     * schedule (null) throws NPE
296 >     * schedule(null) throws NPE
297       */
298 <    public void testScheduleNull() {
299 <        CustomExecutor se = new CustomExecutor(1);
300 <        try {
301 <            TrackedCallable callable = null;
302 <            Future f = se.schedule(callable, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
303 <            shouldThrow();
304 <        } catch(NullPointerException success){}
305 <        catch(Exception e){
256 <            unexpectedException();
298 >    public void testScheduleNull() throws InterruptedException {
299 >        final CustomExecutor p = new CustomExecutor(1);
300 >        try (PoolCleaner cleaner = cleaner(p)) {
301 >            try {
302 >                Future f = p.schedule((Callable)null,
303 >                                      randomTimeout(), randomTimeUnit());
304 >                shouldThrow();
305 >            } catch (NullPointerException success) {}
306          }
258        joinPool(se);
307      }
308  
309      /**
310       * execute throws RejectedExecutionException if shutdown
311       */
312      public void testSchedule1_RejectedExecutionException() {
313 <        CustomExecutor se = new CustomExecutor(1);
314 <        try {
315 <            se.shutdown();
316 <            se.schedule(new NoOpRunnable(),
317 <                        MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
318 <            shouldThrow();
319 <        } catch(RejectedExecutionException success){
320 <        } catch (SecurityException ok) {
313 >        final CustomExecutor p = new CustomExecutor(1);
314 >        try (PoolCleaner cleaner = cleaner(p)) {
315 >            try {
316 >                p.shutdown();
317 >                p.schedule(new NoOpRunnable(),
318 >                           randomTimeout(), randomTimeUnit());
319 >                shouldThrow();
320 >            } catch (RejectedExecutionException success) {
321 >            } catch (SecurityException ok) {}
322          }
274
275        joinPool(se);
276
323      }
324  
325      /**
326       * schedule throws RejectedExecutionException if shutdown
327       */
328      public void testSchedule2_RejectedExecutionException() {
329 <        CustomExecutor se = new CustomExecutor(1);
330 <        try {
331 <            se.shutdown();
332 <            se.schedule(new NoOpCallable(),
333 <                        MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
334 <            shouldThrow();
335 <        } catch(RejectedExecutionException success){
336 <        } catch (SecurityException ok) {
329 >        final CustomExecutor p = new CustomExecutor(1);
330 >        try (PoolCleaner cleaner = cleaner(p)) {
331 >            try {
332 >                p.shutdown();
333 >                p.schedule(new NoOpCallable(),
334 >                           randomTimeout(), randomTimeUnit());
335 >                shouldThrow();
336 >            } catch (RejectedExecutionException success) {
337 >            } catch (SecurityException ok) {}
338          }
292        joinPool(se);
339      }
340  
341      /**
342       * schedule callable throws RejectedExecutionException if shutdown
343       */
344 <     public void testSchedule3_RejectedExecutionException() {
345 <         CustomExecutor se = new CustomExecutor(1);
346 <         try {
347 <            se.shutdown();
348 <            se.schedule(new NoOpCallable(),
349 <                        MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
350 <            shouldThrow();
351 <        } catch(RejectedExecutionException success){
352 <        } catch (SecurityException ok) {
344 >    public void testSchedule3_RejectedExecutionException() {
345 >        final CustomExecutor p = new CustomExecutor(1);
346 >        try (PoolCleaner cleaner = cleaner(p)) {
347 >            try {
348 >                p.shutdown();
349 >                p.schedule(new NoOpCallable(),
350 >                           randomTimeout(), randomTimeUnit());
351 >                shouldThrow();
352 >            } catch (RejectedExecutionException success) {
353 >            } catch (SecurityException ok) {}
354          }
308         joinPool(se);
355      }
356  
357      /**
358 <     *  scheduleAtFixedRate throws RejectedExecutionException if shutdown
358 >     * scheduleAtFixedRate throws RejectedExecutionException if shutdown
359       */
360      public void testScheduleAtFixedRate1_RejectedExecutionException() {
361 <        CustomExecutor se = new CustomExecutor(1);
362 <        try {
363 <            se.shutdown();
364 <            se.scheduleAtFixedRate(new NoOpRunnable(),
365 <                                   MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
366 <            shouldThrow();
367 <        } catch(RejectedExecutionException success){
368 <        } catch (SecurityException ok) {
361 >        final CustomExecutor p = new CustomExecutor(1);
362 >        try (PoolCleaner cleaner = cleaner(p)) {
363 >            try {
364 >                p.shutdown();
365 >                p.scheduleAtFixedRate(new NoOpRunnable(),
366 >                                      MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
367 >                shouldThrow();
368 >            } catch (RejectedExecutionException success) {
369 >            } catch (SecurityException ok) {}
370          }
324        joinPool(se);
371      }
372  
373      /**
374       * scheduleWithFixedDelay throws RejectedExecutionException if shutdown
375       */
376      public void testScheduleWithFixedDelay1_RejectedExecutionException() {
377 <        CustomExecutor se = new CustomExecutor(1);
378 <        try {
379 <            se.shutdown();
380 <            se.scheduleWithFixedDelay(new NoOpRunnable(),
381 <                                      MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
382 <            shouldThrow();
383 <        } catch(RejectedExecutionException success){
384 <        } catch (SecurityException ok) {
377 >        final CustomExecutor p = new CustomExecutor(1);
378 >        try (PoolCleaner cleaner = cleaner(p)) {
379 >            try {
380 >                p.shutdown();
381 >                p.scheduleWithFixedDelay(new NoOpRunnable(),
382 >                                         MEDIUM_DELAY_MS, MEDIUM_DELAY_MS, MILLISECONDS);
383 >                shouldThrow();
384 >            } catch (RejectedExecutionException success) {
385 >            } catch (SecurityException ok) {}
386          }
340        joinPool(se);
387      }
388  
389      /**
390 <     *  getActiveCount increases but doesn't overestimate, when a
391 <     *  thread becomes active
392 <     */
393 <    public void testGetActiveCount() {
394 <        CustomExecutor p2 = new CustomExecutor(2);
395 <        assertEquals(0, p2.getActiveCount());
396 <        p2.execute(new SmallRunnable());
397 <        try {
398 <            Thread.sleep(SHORT_DELAY_MS);
399 <        } catch(Exception e){
400 <            unexpectedException();
390 >     * getActiveCount increases but doesn't overestimate, when a
391 >     * thread becomes active
392 >     */
393 >    public void testGetActiveCount() throws InterruptedException {
394 >        final CountDownLatch done = new CountDownLatch(1);
395 >        final ThreadPoolExecutor p = new CustomExecutor(2);
396 >        try (PoolCleaner cleaner = cleaner(p, done)) {
397 >            final CountDownLatch threadStarted = new CountDownLatch(1);
398 >            assertEquals(0, p.getActiveCount());
399 >            p.execute(new CheckedRunnable() {
400 >                public void realRun() throws InterruptedException {
401 >                    threadStarted.countDown();
402 >                    assertEquals(1, p.getActiveCount());
403 >                    await(done);
404 >                }});
405 >            await(threadStarted);
406 >            assertEquals(1, p.getActiveCount());
407          }
356        assertEquals(1, p2.getActiveCount());
357        joinPool(p2);
408      }
409  
410      /**
411 <     *    getCompletedTaskCount increases, but doesn't overestimate,
412 <     *   when tasks complete
413 <     */
414 <    public void testGetCompletedTaskCount() {
415 <        CustomExecutor p2 = new CustomExecutor(2);
416 <        assertEquals(0, p2.getCompletedTaskCount());
417 <        p2.execute(new SmallRunnable());
418 <        try {
419 <            Thread.sleep(MEDIUM_DELAY_MS);
420 <        } catch(Exception e){
421 <            unexpectedException();
411 >     * getCompletedTaskCount increases, but doesn't overestimate,
412 >     * when tasks complete
413 >     */
414 >    public void testGetCompletedTaskCount() throws InterruptedException {
415 >        final ThreadPoolExecutor p = new CustomExecutor(2);
416 >        try (PoolCleaner cleaner = cleaner(p)) {
417 >            final CountDownLatch threadStarted = new CountDownLatch(1);
418 >            final CountDownLatch threadProceed = new CountDownLatch(1);
419 >            final CountDownLatch threadDone = new CountDownLatch(1);
420 >            assertEquals(0, p.getCompletedTaskCount());
421 >            p.execute(new CheckedRunnable() {
422 >                public void realRun() throws InterruptedException {
423 >                    threadStarted.countDown();
424 >                    assertEquals(0, p.getCompletedTaskCount());
425 >                    await(threadProceed);
426 >                    threadDone.countDown();
427 >                }});
428 >            await(threadStarted);
429 >            assertEquals(0, p.getCompletedTaskCount());
430 >            threadProceed.countDown();
431 >            await(threadDone);
432 >            long startTime = System.nanoTime();
433 >            while (p.getCompletedTaskCount() != 1) {
434 >                if (millisElapsedSince(startTime) > LONG_DELAY_MS)
435 >                    fail("timed out");
436 >                Thread.yield();
437 >            }
438          }
373        assertEquals(1, p2.getCompletedTaskCount());
374        joinPool(p2);
439      }
440  
441      /**
442 <     *  getCorePoolSize returns size given in constructor if not otherwise set
442 >     * getCorePoolSize returns size given in constructor if not otherwise set
443       */
444      public void testGetCorePoolSize() {
445 <        CustomExecutor p1 = new CustomExecutor(1);
446 <        assertEquals(1, p1.getCorePoolSize());
447 <        joinPool(p1);
448 <    }
449 <
450 <    /**
451 <     *    getLargestPoolSize increases, but doesn't overestimate, when
452 <     *   multiple threads active
453 <     */
454 <    public void testGetLargestPoolSize() {
455 <        CustomExecutor p2 = new CustomExecutor(2);
456 <        assertEquals(0, p2.getLargestPoolSize());
457 <        p2.execute(new SmallRunnable());
458 <        p2.execute(new SmallRunnable());
459 <        try {
460 <            Thread.sleep(SHORT_DELAY_MS);
461 <        } catch(Exception e){
462 <            unexpectedException();
463 <        }
464 <        assertEquals(2, p2.getLargestPoolSize());
465 <        joinPool(p2);
466 <    }
467 <
468 <    /**
469 <     *   getPoolSize increases, but doesn't overestimate, when threads
470 <     *   become active
471 <     */
472 <    public void testGetPoolSize() {
473 <        CustomExecutor p1 = new CustomExecutor(1);
474 <        assertEquals(0, p1.getPoolSize());
475 <        p1.execute(new SmallRunnable());
476 <        assertEquals(1, p1.getPoolSize());
477 <        joinPool(p1);
478 <    }
479 <
480 <    /**
481 <     *    getTaskCount increases, but doesn't overestimate, when tasks
482 <     *    submitted
483 <     */
484 <    public void testGetTaskCount() {
485 <        CustomExecutor p1 = new CustomExecutor(1);
486 <        assertEquals(0, p1.getTaskCount());
487 <        for(int i = 0; i < 5; i++)
488 <            p1.execute(new SmallRunnable());
489 <        try {
490 <            Thread.sleep(SHORT_DELAY_MS);
491 <        } catch(Exception e){
492 <            unexpectedException();
445 >        final CustomExecutor p = new CustomExecutor(1);
446 >        try (PoolCleaner cleaner = cleaner(p)) {
447 >            assertEquals(1, p.getCorePoolSize());
448 >        }
449 >    }
450 >
451 >    /**
452 >     * getLargestPoolSize increases, but doesn't overestimate, when
453 >     * multiple threads active
454 >     */
455 >    public void testGetLargestPoolSize() throws InterruptedException {
456 >        final int THREADS = 3;
457 >        final CountDownLatch done = new CountDownLatch(1);
458 >        final ThreadPoolExecutor p = new CustomExecutor(THREADS);
459 >        try (PoolCleaner cleaner = cleaner(p, done)) {
460 >            final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
461 >            assertEquals(0, p.getLargestPoolSize());
462 >            for (int i = 0; i < THREADS; i++)
463 >                p.execute(new CheckedRunnable() {
464 >                    public void realRun() throws InterruptedException {
465 >                        threadsStarted.countDown();
466 >                        await(done);
467 >                        assertEquals(THREADS, p.getLargestPoolSize());
468 >                    }});
469 >            await(threadsStarted);
470 >            assertEquals(THREADS, p.getLargestPoolSize());
471 >        }
472 >        assertEquals(THREADS, p.getLargestPoolSize());
473 >    }
474 >
475 >    /**
476 >     * getPoolSize increases, but doesn't overestimate, when threads
477 >     * become active
478 >     */
479 >    public void testGetPoolSize() throws InterruptedException {
480 >        final CountDownLatch done = new CountDownLatch(1);
481 >        final ThreadPoolExecutor p = new CustomExecutor(1);
482 >        try (PoolCleaner cleaner = cleaner(p, done)) {
483 >            final CountDownLatch threadStarted = new CountDownLatch(1);
484 >            assertEquals(0, p.getPoolSize());
485 >            p.execute(new CheckedRunnable() {
486 >                public void realRun() throws InterruptedException {
487 >                    threadStarted.countDown();
488 >                    assertEquals(1, p.getPoolSize());
489 >                    await(done);
490 >                }});
491 >            await(threadStarted);
492 >            assertEquals(1, p.getPoolSize());
493 >        }
494 >    }
495 >
496 >    /**
497 >     * getTaskCount increases, but doesn't overestimate, when tasks
498 >     * submitted
499 >     */
500 >    public void testGetTaskCount() throws InterruptedException {
501 >        final int TASKS = 3;
502 >        final CountDownLatch done = new CountDownLatch(1);
503 >        final ThreadPoolExecutor p = new CustomExecutor(1);
504 >        try (PoolCleaner cleaner = cleaner(p, done)) {
505 >            final CountDownLatch threadStarted = new CountDownLatch(1);
506 >            assertEquals(0, p.getTaskCount());
507 >            assertEquals(0, p.getCompletedTaskCount());
508 >            p.execute(new CheckedRunnable() {
509 >                public void realRun() throws InterruptedException {
510 >                    threadStarted.countDown();
511 >                    await(done);
512 >                }});
513 >            await(threadStarted);
514 >            assertEquals(1, p.getTaskCount());
515 >            assertEquals(0, p.getCompletedTaskCount());
516 >            for (int i = 0; i < TASKS; i++) {
517 >                assertEquals(1 + i, p.getTaskCount());
518 >                p.execute(new CheckedRunnable() {
519 >                    public void realRun() throws InterruptedException {
520 >                        threadStarted.countDown();
521 >                        assertEquals(1 + TASKS, p.getTaskCount());
522 >                        await(done);
523 >                    }});
524 >            }
525 >            assertEquals(1 + TASKS, p.getTaskCount());
526 >            assertEquals(0, p.getCompletedTaskCount());
527          }
528 <        assertEquals(5, p1.getTaskCount());
529 <        joinPool(p1);
528 >        assertEquals(1 + TASKS, p.getTaskCount());
529 >        assertEquals(1 + TASKS, p.getCompletedTaskCount());
530      }
531  
532      /**
533       * getThreadFactory returns factory in constructor if not set
534       */
535      public void testGetThreadFactory() {
536 <        ThreadFactory tf = new SimpleThreadFactory();
537 <        CustomExecutor p = new CustomExecutor(1, tf);
538 <        assertSame(tf, p.getThreadFactory());
539 <        joinPool(p);
536 >        final ThreadFactory threadFactory = new SimpleThreadFactory();
537 >        final CustomExecutor p = new CustomExecutor(1, threadFactory);
538 >        try (PoolCleaner cleaner = cleaner(p)) {
539 >            assertSame(threadFactory, p.getThreadFactory());
540 >        }
541      }
542  
543      /**
544       * setThreadFactory sets the thread factory returned by getThreadFactory
545       */
546      public void testSetThreadFactory() {
547 <        ThreadFactory tf = new SimpleThreadFactory();
548 <        CustomExecutor p = new CustomExecutor(1);
549 <        p.setThreadFactory(tf);
550 <        assertSame(tf, p.getThreadFactory());
551 <        joinPool(p);
547 >        final ThreadFactory threadFactory = new SimpleThreadFactory();
548 >        final CustomExecutor p = new CustomExecutor(1);
549 >        try (PoolCleaner cleaner = cleaner(p)) {
550 >            p.setThreadFactory(threadFactory);
551 >            assertSame(threadFactory, p.getThreadFactory());
552 >        }
553      }
554  
555      /**
556       * setThreadFactory(null) throws NPE
557       */
558      public void testSetThreadFactoryNull() {
559 <        CustomExecutor p = new CustomExecutor(1);
560 <        try {
561 <            p.setThreadFactory(null);
562 <            shouldThrow();
563 <        } catch (NullPointerException success) {
564 <        } finally {
465 <            joinPool(p);
559 >        final CustomExecutor p = new CustomExecutor(1);
560 >        try (PoolCleaner cleaner = cleaner(p)) {
561 >            try {
562 >                p.setThreadFactory(null);
563 >                shouldThrow();
564 >            } catch (NullPointerException success) {}
565          }
566      }
567  
568      /**
569 <     *   is isShutDown is false before shutdown, true after
569 >     * isShutdown is false before shutdown, true after
570       */
571      public void testIsShutdown() {
572 <
573 <        CustomExecutor p1 = new CustomExecutor(1);
574 <        try {
575 <            assertFalse(p1.isShutdown());
576 <        }
478 <        finally {
479 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
572 >        final CustomExecutor p = new CustomExecutor(1);
573 >        try (PoolCleaner cleaner = cleaner(p)) {
574 >            assertFalse(p.isShutdown());
575 >            try { p.shutdown(); } catch (SecurityException ok) { return; }
576 >            assertTrue(p.isShutdown());
577          }
481        assertTrue(p1.isShutdown());
578      }
579  
484
580      /**
581 <     *   isTerminated is false before termination, true after
582 <     */
583 <    public void testIsTerminated() {
584 <        CustomExecutor p1 = new CustomExecutor(1);
585 <        try {
586 <            p1.execute(new SmallRunnable());
587 <        } finally {
588 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
589 <        }
590 <        try {
591 <            assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS));
592 <            assertTrue(p1.isTerminated());
593 <        } catch(Exception e){
594 <            unexpectedException();
581 >     * isTerminated is false before termination, true after
582 >     */
583 >    public void testIsTerminated() throws InterruptedException {
584 >        final CountDownLatch done = new CountDownLatch(1);
585 >        final ThreadPoolExecutor p = new CustomExecutor(1);
586 >        try (PoolCleaner cleaner = cleaner(p)) {
587 >            final CountDownLatch threadStarted = new CountDownLatch(1);
588 >            p.execute(new CheckedRunnable() {
589 >                public void realRun() throws InterruptedException {
590 >                    assertFalse(p.isTerminated());
591 >                    threadStarted.countDown();
592 >                    await(done);
593 >                }});
594 >            await(threadStarted);
595 >            assertFalse(p.isTerminated());
596 >            assertFalse(p.isTerminating());
597 >            done.countDown();
598 >            try { p.shutdown(); } catch (SecurityException ok) { return; }
599 >            assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
600 >            assertTrue(p.isTerminated());
601          }
602      }
603  
604      /**
605 <     *  isTerminating is not true when running or when terminated
606 <     */
607 <    public void testIsTerminating() {
608 <        CustomExecutor p1 = new CustomExecutor(1);
609 <        assertFalse(p1.isTerminating());
610 <        try {
611 <            p1.execute(new SmallRunnable());
612 <            assertFalse(p1.isTerminating());
613 <        } finally {
614 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
615 <        }
616 <        try {
617 <            assertTrue(p1.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS));
618 <            assertTrue(p1.isTerminated());
619 <            assertFalse(p1.isTerminating());
620 <        } catch(Exception e){
621 <            unexpectedException();
605 >     * isTerminating is not true when running or when terminated
606 >     */
607 >    public void testIsTerminating() throws InterruptedException {
608 >        final CountDownLatch done = new CountDownLatch(1);
609 >        final ThreadPoolExecutor p = new CustomExecutor(1);
610 >        try (PoolCleaner cleaner = cleaner(p)) {
611 >            final CountDownLatch threadStarted = new CountDownLatch(1);
612 >            assertFalse(p.isTerminating());
613 >            p.execute(new CheckedRunnable() {
614 >                public void realRun() throws InterruptedException {
615 >                    assertFalse(p.isTerminating());
616 >                    threadStarted.countDown();
617 >                    await(done);
618 >                }});
619 >            await(threadStarted);
620 >            assertFalse(p.isTerminating());
621 >            done.countDown();
622 >            try { p.shutdown(); } catch (SecurityException ok) { return; }
623 >            assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
624 >            assertTrue(p.isTerminated());
625 >            assertFalse(p.isTerminating());
626          }
627      }
628  
629      /**
630       * getQueue returns the work queue, which contains queued tasks
631       */
632 <    public void testGetQueue() {
633 <        CustomExecutor p1 = new CustomExecutor(1);
634 <        ScheduledFuture[] tasks = new ScheduledFuture[5];
635 <        for(int i = 0; i < 5; i++){
636 <            tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, TimeUnit.MILLISECONDS);
637 <        }
638 <        try {
639 <            Thread.sleep(SHORT_DELAY_MS);
640 <            BlockingQueue<Runnable> q = p1.getQueue();
641 <            assertTrue(q.contains(tasks[4]));
632 >    public void testGetQueue() throws InterruptedException {
633 >        final CountDownLatch done = new CountDownLatch(1);
634 >        final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
635 >        try (PoolCleaner cleaner = cleaner(p, done)) {
636 >            final CountDownLatch threadStarted = new CountDownLatch(1);
637 >            ScheduledFuture[] tasks = new ScheduledFuture[5];
638 >            for (int i = 0; i < tasks.length; i++) {
639 >                Runnable r = new CheckedRunnable() {
640 >                    public void realRun() throws InterruptedException {
641 >                        threadStarted.countDown();
642 >                        await(done);
643 >                    }};
644 >                tasks[i] = p.schedule(r, 1, MILLISECONDS);
645 >            }
646 >            await(threadStarted);
647 >            BlockingQueue<Runnable> q = p.getQueue();
648 >            assertTrue(q.contains(tasks[tasks.length - 1]));
649              assertFalse(q.contains(tasks[0]));
538        } catch(Exception e) {
539            unexpectedException();
540        } finally {
541            joinPool(p1);
650          }
651      }
652  
653      /**
654       * remove(task) removes queued task, and fails to remove active task
655       */
656 <    public void testRemove() {
657 <        CustomExecutor p1 = new CustomExecutor(1);
658 <        ScheduledFuture[] tasks = new ScheduledFuture[5];
659 <        for(int i = 0; i < 5; i++){
660 <            tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), 1, TimeUnit.MILLISECONDS);
661 <        }
662 <        try {
663 <            Thread.sleep(SHORT_DELAY_MS);
664 <            BlockingQueue<Runnable> q = p1.getQueue();
665 <            assertFalse(p1.remove((Runnable)tasks[0]));
656 >    public void testRemove() throws InterruptedException {
657 >        final CountDownLatch done = new CountDownLatch(1);
658 >        final ScheduledThreadPoolExecutor p = new CustomExecutor(1);
659 >        try (PoolCleaner cleaner = cleaner(p, done)) {
660 >            ScheduledFuture[] tasks = new ScheduledFuture[5];
661 >            final CountDownLatch threadStarted = new CountDownLatch(1);
662 >            for (int i = 0; i < tasks.length; i++) {
663 >                Runnable r = new CheckedRunnable() {
664 >                    public void realRun() throws InterruptedException {
665 >                        threadStarted.countDown();
666 >                        await(done);
667 >                    }};
668 >                tasks[i] = p.schedule(r, 1, MILLISECONDS);
669 >            }
670 >            await(threadStarted);
671 >            BlockingQueue<Runnable> q = p.getQueue();
672 >            assertFalse(p.remove((Runnable)tasks[0]));
673              assertTrue(q.contains((Runnable)tasks[4]));
674              assertTrue(q.contains((Runnable)tasks[3]));
675 <            assertTrue(p1.remove((Runnable)tasks[4]));
676 <            assertFalse(p1.remove((Runnable)tasks[4]));
675 >            assertTrue(p.remove((Runnable)tasks[4]));
676 >            assertFalse(p.remove((Runnable)tasks[4]));
677              assertFalse(q.contains((Runnable)tasks[4]));
678              assertTrue(q.contains((Runnable)tasks[3]));
679 <            assertTrue(p1.remove((Runnable)tasks[3]));
679 >            assertTrue(p.remove((Runnable)tasks[3]));
680              assertFalse(q.contains((Runnable)tasks[3]));
566        } catch(Exception e) {
567            unexpectedException();
568        } finally {
569            joinPool(p1);
681          }
682      }
683  
684      /**
685 <     *  purge removes cancelled tasks from the queue
685 >     * purge removes cancelled tasks from the queue
686       */
687 <    public void testPurge() {
688 <        CustomExecutor p1 = new CustomExecutor(1);
689 <        ScheduledFuture[] tasks = new ScheduledFuture[5];
690 <        for(int i = 0; i < 5; i++){
691 <            tasks[i] = p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
692 <        }
693 <        try {
694 <            int max = 5;
687 >    public void testPurge() throws InterruptedException {
688 >        final ScheduledFuture[] tasks = new ScheduledFuture[5];
689 >        final Runnable releaser = new Runnable() { public void run() {
690 >            for (ScheduledFuture task : tasks)
691 >                if (task != null) task.cancel(true); }};
692 >        final CustomExecutor p = new CustomExecutor(1);
693 >        try (PoolCleaner cleaner = cleaner(p, releaser)) {
694 >            for (int i = 0; i < tasks.length; i++)
695 >                tasks[i] = p.schedule(new SmallPossiblyInterruptedRunnable(),
696 >                                      LONG_DELAY_MS, MILLISECONDS);
697 >            int max = tasks.length;
698              if (tasks[4].cancel(true)) --max;
699              if (tasks[3].cancel(true)) --max;
700              // There must eventually be an interference-free point at
701              // which purge will not fail. (At worst, when queue is empty.)
702 <            int k;
703 <            for (k = 0; k < SMALL_DELAY_MS; ++k) {
704 <                p1.purge();
705 <                long count = p1.getTaskCount();
706 <                if (count >= 0 && count <= max)
707 <                    break;
708 <                Thread.sleep(1);
709 <            }
596 <            assertTrue(k < SMALL_DELAY_MS);
597 <        } catch(Exception e) {
598 <            unexpectedException();
599 <        } finally {
600 <            joinPool(p1);
702 >            long startTime = System.nanoTime();
703 >            do {
704 >                p.purge();
705 >                long count = p.getTaskCount();
706 >                if (count == max)
707 >                    return;
708 >            } while (millisElapsedSince(startTime) < LONG_DELAY_MS);
709 >            fail("Purge failed to remove cancelled tasks");
710          }
711      }
712  
713      /**
714 <     *  shutDownNow returns a list containing tasks that were not run
715 <     */
716 <    public void testShutDownNow() {
717 <        CustomExecutor p1 = new CustomExecutor(1);
718 <        for(int i = 0; i < 5; i++)
719 <            p1.schedule(new SmallPossiblyInterruptedRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
720 <        List l;
714 >     * shutdownNow returns a list containing tasks that were not run,
715 >     * and those tasks are drained from the queue
716 >     */
717 >    public void testShutdownNow() throws InterruptedException {
718 >        final int poolSize = 2;
719 >        final int count = 5;
720 >        final AtomicInteger ran = new AtomicInteger(0);
721 >        final CustomExecutor p = new CustomExecutor(poolSize);
722 >        final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
723 >        Runnable waiter = new CheckedRunnable() { public void realRun() {
724 >            threadsStarted.countDown();
725 >            try {
726 >                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
727 >            } catch (InterruptedException success) {}
728 >            ran.getAndIncrement();
729 >        }};
730 >        for (int i = 0; i < count; i++)
731 >            p.execute(waiter);
732 >        await(threadsStarted);
733 >        assertEquals(poolSize, p.getActiveCount());
734 >        assertEquals(0, p.getCompletedTaskCount());
735 >        final List<Runnable> queuedTasks;
736          try {
737 <            l = p1.shutdownNow();
737 >            queuedTasks = p.shutdownNow();
738          } catch (SecurityException ok) {
739 <            return;
739 >            return; // Allowed in case test doesn't have privs
740          }
741 <        assertTrue(p1.isShutdown());
742 <        assertTrue(l.size() > 0 && l.size() <= 5);
743 <        joinPool(p1);
741 >        assertTrue(p.isShutdown());
742 >        assertTrue(p.getQueue().isEmpty());
743 >        assertEquals(count - poolSize, queuedTasks.size());
744 >        assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
745 >        assertTrue(p.isTerminated());
746 >        assertEquals(poolSize, ran.get());
747 >        assertEquals(poolSize, p.getCompletedTaskCount());
748      }
749  
750      /**
751 <     * In default setting, shutdown cancels periodic but not delayed
752 <     * tasks at shutdown
753 <     */
754 <    public void testShutDown1() {
751 >     * shutdownNow returns a list containing tasks that were not run,
752 >     * and those tasks are drained from the queue
753 >     */
754 >    public void testShutdownNow_delayedTasks() throws InterruptedException {
755 >        final CustomExecutor p = new CustomExecutor(1);
756 >        List<ScheduledFuture> tasks = new ArrayList<>();
757 >        for (int i = 0; i < 3; i++) {
758 >            Runnable r = new NoOpRunnable();
759 >            tasks.add(p.schedule(r, 9, SECONDS));
760 >            tasks.add(p.scheduleAtFixedRate(r, 9, 9, SECONDS));
761 >            tasks.add(p.scheduleWithFixedDelay(r, 9, 9, SECONDS));
762 >        }
763 >        if (testImplementationDetails)
764 >            assertEquals(new HashSet(tasks), new HashSet(p.getQueue()));
765 >        final List<Runnable> queuedTasks;
766          try {
767 <            CustomExecutor p1 = new CustomExecutor(1);
768 <            assertTrue(p1.getExecuteExistingDelayedTasksAfterShutdownPolicy());
769 <            assertFalse(p1.getContinueExistingPeriodicTasksAfterShutdownPolicy());
631 <
632 <            ScheduledFuture[] tasks = new ScheduledFuture[5];
633 <            for(int i = 0; i < 5; i++)
634 <                tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
635 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
636 <            BlockingQueue q = p1.getQueue();
637 <            for (Iterator it = q.iterator(); it.hasNext();) {
638 <                ScheduledFuture t = (ScheduledFuture)it.next();
639 <                assertFalse(t.isCancelled());
640 <            }
641 <            assertTrue(p1.isShutdown());
642 <            Thread.sleep(SMALL_DELAY_MS);
643 <            for (int i = 0; i < 5; ++i) {
644 <                assertTrue(tasks[i].isDone());
645 <                assertFalse(tasks[i].isCancelled());
646 <            }
647 <
767 >            queuedTasks = p.shutdownNow();
768 >        } catch (SecurityException ok) {
769 >            return; // Allowed in case test doesn't have privs
770          }
771 <        catch(Exception ex) {
772 <            unexpectedException();
771 >        assertTrue(p.isShutdown());
772 >        assertTrue(p.getQueue().isEmpty());
773 >        if (testImplementationDetails)
774 >            assertEquals(new HashSet(tasks), new HashSet(queuedTasks));
775 >        assertEquals(tasks.size(), queuedTasks.size());
776 >        for (ScheduledFuture task : tasks) {
777 >            assertFalse(((CustomTask)task).ran);
778 >            assertFalse(task.isDone());
779 >            assertFalse(task.isCancelled());
780          }
781 +        assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
782 +        assertTrue(p.isTerminated());
783      }
784  
654
785      /**
786 <     * If setExecuteExistingDelayedTasksAfterShutdownPolicy is false,
787 <     * delayed tasks are cancelled at shutdown
788 <     */
789 <    public void testShutDown2() {
790 <        try {
791 <            CustomExecutor p1 = new CustomExecutor(1);
792 <            p1.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
793 <            ScheduledFuture[] tasks = new ScheduledFuture[5];
794 <            for(int i = 0; i < 5; i++)
795 <                tasks[i] = p1.schedule(new NoOpRunnable(), SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
796 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
797 <            assertTrue(p1.isShutdown());
798 <            BlockingQueue q = p1.getQueue();
799 <            assertTrue(q.isEmpty());
800 <            Thread.sleep(SMALL_DELAY_MS);
801 <            assertTrue(p1.isTerminated());
802 <        }
803 <        catch(Exception ex) {
804 <            unexpectedException();
786 >     * By default, periodic tasks are cancelled at shutdown.
787 >     * By default, delayed tasks keep running after shutdown.
788 >     * Check that changing the default values work:
789 >     * - setExecuteExistingDelayedTasksAfterShutdownPolicy
790 >     * - setContinueExistingPeriodicTasksAfterShutdownPolicy
791 >     */
792 >    public void testShutdown_cancellation() throws Exception {
793 >        final int poolSize = 4;
794 >        final CustomExecutor p = new CustomExecutor(poolSize);
795 >        final BlockingQueue<Runnable> q = p.getQueue();
796 >        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
797 >        final long delay = rnd.nextInt(2);
798 >        final int rounds = rnd.nextInt(1, 3);
799 >        final boolean effectiveDelayedPolicy;
800 >        final boolean effectivePeriodicPolicy;
801 >        final boolean effectiveRemovePolicy;
802 >
803 >        if (rnd.nextBoolean())
804 >            p.setExecuteExistingDelayedTasksAfterShutdownPolicy(
805 >                effectiveDelayedPolicy = rnd.nextBoolean());
806 >        else
807 >            effectiveDelayedPolicy = true;
808 >        assertEquals(effectiveDelayedPolicy,
809 >                     p.getExecuteExistingDelayedTasksAfterShutdownPolicy());
810 >
811 >        if (rnd.nextBoolean())
812 >            p.setContinueExistingPeriodicTasksAfterShutdownPolicy(
813 >                effectivePeriodicPolicy = rnd.nextBoolean());
814 >        else
815 >            effectivePeriodicPolicy = false;
816 >        assertEquals(effectivePeriodicPolicy,
817 >                     p.getContinueExistingPeriodicTasksAfterShutdownPolicy());
818 >
819 >        if (rnd.nextBoolean())
820 >            p.setRemoveOnCancelPolicy(
821 >                effectiveRemovePolicy = rnd.nextBoolean());
822 >        else
823 >            effectiveRemovePolicy = false;
824 >        assertEquals(effectiveRemovePolicy,
825 >                     p.getRemoveOnCancelPolicy());
826 >
827 >        final boolean periodicTasksContinue = effectivePeriodicPolicy && rnd.nextBoolean();
828 >
829 >        // Strategy: Wedge the pool with one wave of "blocker" tasks,
830 >        // then add a second wave that waits in the queue until unblocked.
831 >        final AtomicInteger ran = new AtomicInteger(0);
832 >        final CountDownLatch poolBlocked = new CountDownLatch(poolSize);
833 >        final CountDownLatch unblock = new CountDownLatch(1);
834 >        final RuntimeException exception = new RuntimeException();
835 >
836 >        class Task implements Runnable {
837 >            public void run() {
838 >                try {
839 >                    ran.getAndIncrement();
840 >                    poolBlocked.countDown();
841 >                    await(unblock);
842 >                } catch (Throwable fail) { threadUnexpectedException(fail); }
843 >            }
844          }
676    }
845  
846 <
847 <    /**
848 <     * If setContinueExistingPeriodicTasksAfterShutdownPolicy is set false,
849 <     * periodic tasks are not cancelled at shutdown
850 <     */
851 <    public void testShutDown3() {
852 <        try {
853 <            CustomExecutor p1 = new CustomExecutor(1);
854 <            p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
687 <            ScheduledFuture task =
688 <                p1.scheduleAtFixedRate(new NoOpRunnable(), 5, 5, TimeUnit.MILLISECONDS);
689 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
690 <            assertTrue(p1.isShutdown());
691 <            BlockingQueue q = p1.getQueue();
692 <            assertTrue(q.isEmpty());
693 <            Thread.sleep(SHORT_DELAY_MS);
694 <            assertTrue(p1.isTerminated());
695 <        }
696 <        catch(Exception ex) {
697 <            unexpectedException();
846 >        class PeriodicTask extends Task {
847 >            PeriodicTask(int rounds) { this.rounds = rounds; }
848 >            int rounds;
849 >            public void run() {
850 >                if (--rounds == 0) super.run();
851 >                // throw exception to surely terminate this periodic task,
852 >                // but in a separate execution and in a detectable way.
853 >                if (rounds == -1) throw exception;
854 >            }
855          }
699    }
856  
857 <    /**
858 <     * if setContinueExistingPeriodicTasksAfterShutdownPolicy is true,
859 <     * periodic tasks are cancelled at shutdown
860 <     */
861 <    public void testShutDown4() {
862 <        CustomExecutor p1 = new CustomExecutor(1);
863 <        try {
864 <            p1.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
865 <            ScheduledFuture task =
866 <                p1.scheduleAtFixedRate(new NoOpRunnable(), 1, 1, TimeUnit.MILLISECONDS);
867 <            assertFalse(task.isCancelled());
868 <            try { p1.shutdown(); } catch(SecurityException ok) { return; }
869 <            assertFalse(task.isCancelled());
870 <            assertFalse(p1.isTerminated());
871 <            assertTrue(p1.isShutdown());
872 <            Thread.sleep(SHORT_DELAY_MS);
873 <            assertFalse(task.isCancelled());
874 <            assertTrue(task.cancel(true));
875 <            assertTrue(task.isDone());
876 <            Thread.sleep(SHORT_DELAY_MS);
877 <            assertTrue(p1.isTerminated());
878 <        }
879 <        catch(Exception ex) {
880 <            unexpectedException();
881 <        }
882 <        finally {
883 <            joinPool(p1);
884 <        }
857 >        Runnable task = new Task();
858 >
859 >        List<Future<?>> immediates = new ArrayList<>();
860 >        List<Future<?>> delayeds   = new ArrayList<>();
861 >        List<Future<?>> periodics  = new ArrayList<>();
862 >
863 >        immediates.add(p.submit(task));
864 >        delayeds.add(p.schedule(task, delay, MILLISECONDS));
865 >        periodics.add(p.scheduleAtFixedRate(
866 >                          new PeriodicTask(rounds), delay, 1, MILLISECONDS));
867 >        periodics.add(p.scheduleWithFixedDelay(
868 >                          new PeriodicTask(rounds), delay, 1, MILLISECONDS));
869 >
870 >        await(poolBlocked);
871 >
872 >        assertEquals(poolSize, ran.get());
873 >        assertEquals(poolSize, p.getActiveCount());
874 >        assertTrue(q.isEmpty());
875 >
876 >        // Add second wave of tasks.
877 >        immediates.add(p.submit(task));
878 >        delayeds.add(p.schedule(task, effectiveDelayedPolicy ? delay : LONG_DELAY_MS, MILLISECONDS));
879 >        periodics.add(p.scheduleAtFixedRate(
880 >                          new PeriodicTask(rounds), delay, 1, MILLISECONDS));
881 >        periodics.add(p.scheduleWithFixedDelay(
882 >                          new PeriodicTask(rounds), delay, 1, MILLISECONDS));
883 >
884 >        assertEquals(poolSize, q.size());
885 >        assertEquals(poolSize, ran.get());
886 >
887 >        immediates.forEach(
888 >            f -> assertTrue(((ScheduledFuture)f).getDelay(NANOSECONDS) <= 0L));
889 >
890 >        Stream.of(immediates, delayeds, periodics).flatMap(c -> c.stream())
891 >            .forEach(f -> assertFalse(f.isDone()));
892 >
893 >        try { p.shutdown(); } catch (SecurityException ok) { return; }
894 >        assertTrue(p.isShutdown());
895 >        assertTrue(p.isTerminating());
896 >        assertFalse(p.isTerminated());
897 >
898 >        if (rnd.nextBoolean())
899 >            assertThrows(
900 >                RejectedExecutionException.class,
901 >                () -> p.submit(task),
902 >                () -> p.schedule(task, 1, SECONDS),
903 >                () -> p.scheduleAtFixedRate(
904 >                    new PeriodicTask(1), 1, 1, SECONDS),
905 >                () -> p.scheduleWithFixedDelay(
906 >                    new PeriodicTask(2), 1, 1, SECONDS));
907 >
908 >        assertTrue(q.contains(immediates.get(1)));
909 >        assertTrue(!effectiveDelayedPolicy
910 >                   ^ q.contains(delayeds.get(1)));
911 >        assertTrue(!effectivePeriodicPolicy
912 >                   ^ q.containsAll(periodics.subList(2, 4)));
913 >
914 >        immediates.forEach(f -> assertFalse(f.isDone()));
915 >
916 >        assertFalse(delayeds.get(0).isDone());
917 >        if (effectiveDelayedPolicy)
918 >            assertFalse(delayeds.get(1).isDone());
919 >        else
920 >            assertTrue(delayeds.get(1).isCancelled());
921 >
922 >        if (effectivePeriodicPolicy)
923 >            periodics.forEach(
924 >                f -> {
925 >                    assertFalse(f.isDone());
926 >                    if (!periodicTasksContinue) {
927 >                        assertTrue(f.cancel(false));
928 >                        assertTrue(f.isCancelled());
929 >                    }
930 >                });
931 >        else {
932 >            periodics.subList(0, 2).forEach(f -> assertFalse(f.isDone()));
933 >            periodics.subList(2, 4).forEach(f -> assertTrue(f.isCancelled()));
934 >        }
935 >
936 >        unblock.countDown();    // Release all pool threads
937 >
938 >        assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
939 >        assertFalse(p.isTerminating());
940 >        assertTrue(p.isTerminated());
941 >
942 >        assertTrue(q.isEmpty());
943 >
944 >        Stream.of(immediates, delayeds, periodics).flatMap(c -> c.stream())
945 >            .forEach(f -> assertTrue(f.isDone()));
946 >
947 >        for (Future<?> f : immediates) assertNull(f.get());
948 >
949 >        assertNull(delayeds.get(0).get());
950 >        if (effectiveDelayedPolicy)
951 >            assertNull(delayeds.get(1).get());
952 >        else
953 >            assertTrue(delayeds.get(1).isCancelled());
954 >
955 >        if (periodicTasksContinue)
956 >            periodics.forEach(
957 >                f -> {
958 >                    try { f.get(); }
959 >                    catch (ExecutionException success) {
960 >                        assertSame(exception, success.getCause());
961 >                    }
962 >                    catch (Throwable fail) { threadUnexpectedException(fail); }
963 >                });
964 >        else
965 >            periodics.forEach(f -> assertTrue(f.isCancelled()));
966 >
967 >        assertEquals(poolSize + 1
968 >                     + (effectiveDelayedPolicy ? 1 : 0)
969 >                     + (periodicTasksContinue ? 2 : 0),
970 >                     ran.get());
971      }
972  
973      /**
974       * completed submit of callable returns result
975       */
976 <    public void testSubmitCallable() {
977 <        ExecutorService e = new CustomExecutor(2);
978 <        try {
976 >    public void testSubmitCallable() throws Exception {
977 >        final ExecutorService e = new CustomExecutor(2);
978 >        try (PoolCleaner cleaner = cleaner(e)) {
979              Future<String> future = e.submit(new StringTask());
980              String result = future.get();
981              assertSame(TEST_STRING, result);
982          }
741        catch (ExecutionException ex) {
742            unexpectedException();
743        }
744        catch (InterruptedException ex) {
745            unexpectedException();
746        } finally {
747            joinPool(e);
748        }
983      }
984  
985      /**
986       * completed submit of runnable returns successfully
987       */
988 <    public void testSubmitRunnable() {
989 <        ExecutorService e = new CustomExecutor(2);
990 <        try {
988 >    public void testSubmitRunnable() throws Exception {
989 >        final ExecutorService e = new CustomExecutor(2);
990 >        try (PoolCleaner cleaner = cleaner(e)) {
991              Future<?> future = e.submit(new NoOpRunnable());
992              future.get();
993              assertTrue(future.isDone());
994          }
761        catch (ExecutionException ex) {
762            unexpectedException();
763        }
764        catch (InterruptedException ex) {
765            unexpectedException();
766        } finally {
767            joinPool(e);
768        }
995      }
996  
997      /**
998       * completed submit of (runnable, result) returns result
999       */
1000 <    public void testSubmitRunnable2() {
1001 <        ExecutorService e = new CustomExecutor(2);
1002 <        try {
1000 >    public void testSubmitRunnable2() throws Exception {
1001 >        final ExecutorService e = new CustomExecutor(2);
1002 >        try (PoolCleaner cleaner = cleaner(e)) {
1003              Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
1004              String result = future.get();
1005              assertSame(TEST_STRING, result);
1006          }
781        catch (ExecutionException ex) {
782            unexpectedException();
783        }
784        catch (InterruptedException ex) {
785            unexpectedException();
786        } finally {
787            joinPool(e);
788        }
1007      }
1008  
1009      /**
1010       * invokeAny(null) throws NPE
1011       */
1012 <    public void testInvokeAny1() {
1013 <        ExecutorService e = new CustomExecutor(2);
1014 <        try {
1015 <            e.invokeAny(null);
1016 <        } catch (NullPointerException success) {
1017 <        } catch(Exception ex) {
1018 <            unexpectedException();
801 <        } finally {
802 <            joinPool(e);
1012 >    public void testInvokeAny1() throws Exception {
1013 >        final ExecutorService e = new CustomExecutor(2);
1014 >        try (PoolCleaner cleaner = cleaner(e)) {
1015 >            try {
1016 >                e.invokeAny(null);
1017 >                shouldThrow();
1018 >            } catch (NullPointerException success) {}
1019          }
1020      }
1021  
1022      /**
1023 <     * invokeAny(empty collection) throws IAE
1024 <     */
1025 <    public void testInvokeAny2() {
1026 <        ExecutorService e = new CustomExecutor(2);
1027 <        try {
1028 <            e.invokeAny(new ArrayList<Callable<String>>());
1029 <        } catch (IllegalArgumentException success) {
1030 <        } catch(Exception ex) {
1031 <            unexpectedException();
816 <        } finally {
817 <            joinPool(e);
1023 >     * invokeAny(empty collection) throws IllegalArgumentException
1024 >     */
1025 >    public void testInvokeAny2() throws Exception {
1026 >        final ExecutorService e = new CustomExecutor(2);
1027 >        try (PoolCleaner cleaner = cleaner(e)) {
1028 >            try {
1029 >                e.invokeAny(new ArrayList<Callable<String>>());
1030 >                shouldThrow();
1031 >            } catch (IllegalArgumentException success) {}
1032          }
1033      }
1034  
1035      /**
1036       * invokeAny(c) throws NPE if c has null elements
1037       */
1038 <    public void testInvokeAny3() {
1039 <        ExecutorService e = new CustomExecutor(2);
1040 <        try {
1041 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1042 <            l.add(new StringTask());
1038 >    public void testInvokeAny3() throws Exception {
1039 >        final CountDownLatch latch = new CountDownLatch(1);
1040 >        final ExecutorService e = new CustomExecutor(2);
1041 >        try (PoolCleaner cleaner = cleaner(e)) {
1042 >            List<Callable<String>> l = new ArrayList<>();
1043 >            l.add(latchAwaitingStringTask(latch));
1044              l.add(null);
1045 <            e.invokeAny(l);
1046 <        } catch (NullPointerException success) {
1047 <        } catch(Exception ex) {
1048 <            unexpectedException();
1049 <        } finally {
835 <            joinPool(e);
1045 >            try {
1046 >                e.invokeAny(l);
1047 >                shouldThrow();
1048 >            } catch (NullPointerException success) {}
1049 >            latch.countDown();
1050          }
1051      }
1052  
1053      /**
1054       * invokeAny(c) throws ExecutionException if no task completes
1055       */
1056 <    public void testInvokeAny4() {
1057 <        ExecutorService e = new CustomExecutor(2);
1058 <        try {
1059 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1056 >    public void testInvokeAny4() throws Exception {
1057 >        final ExecutorService e = new CustomExecutor(2);
1058 >        try (PoolCleaner cleaner = cleaner(e)) {
1059 >            List<Callable<String>> l = new ArrayList<>();
1060              l.add(new NPETask());
1061 <            e.invokeAny(l);
1062 <        } catch (ExecutionException success) {
1063 <        } catch(Exception ex) {
1064 <            unexpectedException();
1065 <        } finally {
1066 <            joinPool(e);
1061 >            try {
1062 >                e.invokeAny(l);
1063 >                shouldThrow();
1064 >            } catch (ExecutionException success) {
1065 >                assertTrue(success.getCause() instanceof NullPointerException);
1066 >            }
1067          }
1068      }
1069  
1070      /**
1071       * invokeAny(c) returns result of some task
1072       */
1073 <    public void testInvokeAny5() {
1074 <        ExecutorService e = new CustomExecutor(2);
1075 <        try {
1076 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1073 >    public void testInvokeAny5() throws Exception {
1074 >        final ExecutorService e = new CustomExecutor(2);
1075 >        try (PoolCleaner cleaner = cleaner(e)) {
1076 >            List<Callable<String>> l = new ArrayList<>();
1077              l.add(new StringTask());
1078              l.add(new StringTask());
1079              String result = e.invokeAny(l);
1080              assertSame(TEST_STRING, result);
867        } catch (ExecutionException success) {
868        } catch(Exception ex) {
869            unexpectedException();
870        } finally {
871            joinPool(e);
1081          }
1082      }
1083  
1084      /**
1085       * invokeAll(null) throws NPE
1086       */
1087 <    public void testInvokeAll1() {
1088 <        ExecutorService e = new CustomExecutor(2);
1089 <        try {
1090 <            e.invokeAll(null);
1091 <        } catch (NullPointerException success) {
1092 <        } catch(Exception ex) {
1093 <            unexpectedException();
885 <        } finally {
886 <            joinPool(e);
1087 >    public void testInvokeAll1() throws Exception {
1088 >        final ExecutorService e = new CustomExecutor(2);
1089 >        try (PoolCleaner cleaner = cleaner(e)) {
1090 >            try {
1091 >                e.invokeAll(null);
1092 >                shouldThrow();
1093 >            } catch (NullPointerException success) {}
1094          }
1095      }
1096  
1097      /**
1098 <     * invokeAll(empty collection) returns empty collection
1098 >     * invokeAll(empty collection) returns empty list
1099       */
1100 <    public void testInvokeAll2() {
1101 <        ExecutorService e = new CustomExecutor(2);
1102 <        try {
1103 <            List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>());
1100 >    public void testInvokeAll2() throws Exception {
1101 >        final ExecutorService e = new CustomExecutor(2);
1102 >        final Collection<Callable<String>> emptyCollection
1103 >            = Collections.emptyList();
1104 >        try (PoolCleaner cleaner = cleaner(e)) {
1105 >            List<Future<String>> r = e.invokeAll(emptyCollection);
1106              assertTrue(r.isEmpty());
898        } catch(Exception ex) {
899            unexpectedException();
900        } finally {
901            joinPool(e);
1107          }
1108      }
1109  
1110      /**
1111       * invokeAll(c) throws NPE if c has null elements
1112       */
1113 <    public void testInvokeAll3() {
1114 <        ExecutorService e = new CustomExecutor(2);
1115 <        try {
1116 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1113 >    public void testInvokeAll3() throws Exception {
1114 >        final ExecutorService e = new CustomExecutor(2);
1115 >        try (PoolCleaner cleaner = cleaner(e)) {
1116 >            List<Callable<String>> l = new ArrayList<>();
1117              l.add(new StringTask());
1118              l.add(null);
1119 <            e.invokeAll(l);
1120 <        } catch (NullPointerException success) {
1121 <        } catch(Exception ex) {
1122 <            unexpectedException();
918 <        } finally {
919 <            joinPool(e);
1119 >            try {
1120 >                e.invokeAll(l);
1121 >                shouldThrow();
1122 >            } catch (NullPointerException success) {}
1123          }
1124      }
1125  
1126      /**
1127       * get of invokeAll(c) throws exception on failed task
1128       */
1129 <    public void testInvokeAll4() {
1130 <        ExecutorService e = new CustomExecutor(2);
1131 <        try {
1132 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1129 >    public void testInvokeAll4() throws Exception {
1130 >        final ExecutorService e = new CustomExecutor(2);
1131 >        try (PoolCleaner cleaner = cleaner(e)) {
1132 >            List<Callable<String>> l = new ArrayList<>();
1133              l.add(new NPETask());
1134 <            List<Future<String>> result = e.invokeAll(l);
1135 <            assertEquals(1, result.size());
1136 <            for (Iterator<Future<String>> it = result.iterator(); it.hasNext();)
1137 <                it.next().get();
1138 <        } catch(ExecutionException success) {
1139 <        } catch(Exception ex) {
1140 <            unexpectedException();
1141 <        } finally {
939 <            joinPool(e);
1134 >            List<Future<String>> futures = e.invokeAll(l);
1135 >            assertEquals(1, futures.size());
1136 >            try {
1137 >                futures.get(0).get();
1138 >                shouldThrow();
1139 >            } catch (ExecutionException success) {
1140 >                assertTrue(success.getCause() instanceof NullPointerException);
1141 >            }
1142          }
1143      }
1144  
1145      /**
1146       * invokeAll(c) returns results of all completed tasks
1147       */
1148 <    public void testInvokeAll5() {
1149 <        ExecutorService e = new CustomExecutor(2);
1150 <        try {
1151 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1148 >    public void testInvokeAll5() throws Exception {
1149 >        final ExecutorService e = new CustomExecutor(2);
1150 >        try (PoolCleaner cleaner = cleaner(e)) {
1151 >            List<Callable<String>> l = new ArrayList<>();
1152              l.add(new StringTask());
1153              l.add(new StringTask());
1154 <            List<Future<String>> result = e.invokeAll(l);
1155 <            assertEquals(2, result.size());
1156 <            for (Iterator<Future<String>> it = result.iterator(); it.hasNext();)
1157 <                assertSame(TEST_STRING, it.next().get());
956 <        } catch (ExecutionException success) {
957 <        } catch(Exception ex) {
958 <            unexpectedException();
959 <        } finally {
960 <            joinPool(e);
1154 >            List<Future<String>> futures = e.invokeAll(l);
1155 >            assertEquals(2, futures.size());
1156 >            for (Future<String> future : futures)
1157 >                assertSame(TEST_STRING, future.get());
1158          }
1159      }
1160  
1161      /**
1162       * timed invokeAny(null) throws NPE
1163       */
1164 <    public void testTimedInvokeAny1() {
1165 <        ExecutorService e = new CustomExecutor(2);
1166 <        try {
1167 <            e.invokeAny(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1168 <        } catch (NullPointerException success) {
1169 <        } catch(Exception ex) {
1170 <            unexpectedException();
974 <        } finally {
975 <            joinPool(e);
1164 >    public void testTimedInvokeAny1() throws Exception {
1165 >        final ExecutorService e = new CustomExecutor(2);
1166 >        try (PoolCleaner cleaner = cleaner(e)) {
1167 >            try {
1168 >                e.invokeAny(null, randomTimeout(), randomTimeUnit());
1169 >                shouldThrow();
1170 >            } catch (NullPointerException success) {}
1171          }
1172      }
1173  
1174      /**
1175       * timed invokeAny(,,null) throws NPE
1176       */
1177 <    public void testTimedInvokeAnyNullTimeUnit() {
1178 <        ExecutorService e = new CustomExecutor(2);
1179 <        try {
1180 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1177 >    public void testTimedInvokeAnyNullTimeUnit() throws Exception {
1178 >        final ExecutorService e = new CustomExecutor(2);
1179 >        try (PoolCleaner cleaner = cleaner(e)) {
1180 >            List<Callable<String>> l = new ArrayList<>();
1181              l.add(new StringTask());
1182 <            e.invokeAny(l, MEDIUM_DELAY_MS, null);
1183 <        } catch (NullPointerException success) {
1184 <        } catch(Exception ex) {
1185 <            unexpectedException();
991 <        } finally {
992 <            joinPool(e);
1182 >            try {
1183 >                e.invokeAny(l, randomTimeout(), null);
1184 >                shouldThrow();
1185 >            } catch (NullPointerException success) {}
1186          }
1187      }
1188  
1189      /**
1190 <     * timed invokeAny(empty collection) throws IAE
1190 >     * timed invokeAny(empty collection) throws IllegalArgumentException
1191       */
1192 <    public void testTimedInvokeAny2() {
1193 <        ExecutorService e = new CustomExecutor(2);
1194 <        try {
1195 <            e.invokeAny(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1196 <        } catch (IllegalArgumentException success) {
1197 <        } catch(Exception ex) {
1198 <            unexpectedException();
1199 <        } finally {
1200 <            joinPool(e);
1192 >    public void testTimedInvokeAny2() throws Exception {
1193 >        final ExecutorService e = new CustomExecutor(2);
1194 >        final Collection<Callable<String>> emptyCollection
1195 >            = Collections.emptyList();
1196 >        try (PoolCleaner cleaner = cleaner(e)) {
1197 >            try {
1198 >                e.invokeAny(emptyCollection, randomTimeout(), randomTimeUnit());
1199 >                shouldThrow();
1200 >            } catch (IllegalArgumentException success) {}
1201          }
1202      }
1203  
1204      /**
1205       * timed invokeAny(c) throws NPE if c has null elements
1206       */
1207 <    public void testTimedInvokeAny3() {
1208 <        ExecutorService e = new CustomExecutor(2);
1209 <        try {
1210 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1211 <            l.add(new StringTask());
1207 >    public void testTimedInvokeAny3() throws Exception {
1208 >        CountDownLatch latch = new CountDownLatch(1);
1209 >        final ExecutorService e = new CustomExecutor(2);
1210 >        try (PoolCleaner cleaner = cleaner(e)) {
1211 >            List<Callable<String>> l = new ArrayList<>();
1212 >            l.add(latchAwaitingStringTask(latch));
1213              l.add(null);
1214 <            e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1215 <        } catch (NullPointerException success) {
1216 <        } catch(Exception ex) {
1217 <            ex.printStackTrace();
1218 <            unexpectedException();
1025 <        } finally {
1026 <            joinPool(e);
1214 >            try {
1215 >                e.invokeAny(l, randomTimeout(), randomTimeUnit());
1216 >                shouldThrow();
1217 >            } catch (NullPointerException success) {}
1218 >            latch.countDown();
1219          }
1220      }
1221  
1222      /**
1223       * timed invokeAny(c) throws ExecutionException if no task completes
1224       */
1225 <    public void testTimedInvokeAny4() {
1226 <        ExecutorService e = new CustomExecutor(2);
1227 <        try {
1228 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1225 >    public void testTimedInvokeAny4() throws Exception {
1226 >        final ExecutorService e = new CustomExecutor(2);
1227 >        try (PoolCleaner cleaner = cleaner(e)) {
1228 >            long startTime = System.nanoTime();
1229 >            List<Callable<String>> l = new ArrayList<>();
1230              l.add(new NPETask());
1231 <            e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1232 <        } catch(ExecutionException success) {
1233 <        } catch(Exception ex) {
1234 <            unexpectedException();
1235 <        } finally {
1236 <            joinPool(e);
1231 >            try {
1232 >                e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
1233 >                shouldThrow();
1234 >            } catch (ExecutionException success) {
1235 >                assertTrue(success.getCause() instanceof NullPointerException);
1236 >            }
1237 >            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
1238          }
1239      }
1240  
1241      /**
1242       * timed invokeAny(c) returns result of some task
1243       */
1244 <    public void testTimedInvokeAny5() {
1245 <        ExecutorService e = new CustomExecutor(2);
1246 <        try {
1247 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1244 >    public void testTimedInvokeAny5() throws Exception {
1245 >        final ExecutorService e = new CustomExecutor(2);
1246 >        try (PoolCleaner cleaner = cleaner(e)) {
1247 >            long startTime = System.nanoTime();
1248 >            List<Callable<String>> l = new ArrayList<>();
1249              l.add(new StringTask());
1250              l.add(new StringTask());
1251 <            String result = e.invokeAny(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1251 >            String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
1252              assertSame(TEST_STRING, result);
1253 <        } catch (ExecutionException success) {
1059 <        } catch(Exception ex) {
1060 <            unexpectedException();
1061 <        } finally {
1062 <            joinPool(e);
1253 >            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
1254          }
1255      }
1256  
1257      /**
1258 <     * timed invokeAll(null) throws NPE
1258 >     * timed invokeAll(null) throws NullPointerException
1259       */
1260 <    public void testTimedInvokeAll1() {
1261 <        ExecutorService e = new CustomExecutor(2);
1262 <        try {
1263 <            e.invokeAll(null, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1264 <        } catch (NullPointerException success) {
1265 <        } catch(Exception ex) {
1266 <            unexpectedException();
1076 <        } finally {
1077 <            joinPool(e);
1260 >    public void testTimedInvokeAll1() throws Exception {
1261 >        final ExecutorService e = new CustomExecutor(2);
1262 >        try (PoolCleaner cleaner = cleaner(e)) {
1263 >            try {
1264 >                e.invokeAll(null, randomTimeout(), randomTimeUnit());
1265 >                shouldThrow();
1266 >            } catch (NullPointerException success) {}
1267          }
1268      }
1269  
1270      /**
1271 <     * timed invokeAll(,,null) throws NPE
1271 >     * timed invokeAll(,,null) throws NullPointerException
1272       */
1273 <    public void testTimedInvokeAllNullTimeUnit() {
1274 <        ExecutorService e = new CustomExecutor(2);
1275 <        try {
1276 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1273 >    public void testTimedInvokeAllNullTimeUnit() throws Exception {
1274 >        final ExecutorService e = new CustomExecutor(2);
1275 >        try (PoolCleaner cleaner = cleaner(e)) {
1276 >            List<Callable<String>> l = new ArrayList<>();
1277              l.add(new StringTask());
1278 <            e.invokeAll(l, MEDIUM_DELAY_MS, null);
1279 <        } catch (NullPointerException success) {
1280 <        } catch(Exception ex) {
1281 <            unexpectedException();
1093 <        } finally {
1094 <            joinPool(e);
1278 >            try {
1279 >                e.invokeAll(l, randomTimeout(), null);
1280 >                shouldThrow();
1281 >            } catch (NullPointerException success) {}
1282          }
1283      }
1284  
1285      /**
1286 <     * timed invokeAll(empty collection) returns empty collection
1286 >     * timed invokeAll(empty collection) returns empty list
1287       */
1288 <    public void testTimedInvokeAll2() {
1289 <        ExecutorService e = new CustomExecutor(2);
1290 <        try {
1291 <            List<Future<String>> r = e.invokeAll(new ArrayList<Callable<String>>(), MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1288 >    public void testTimedInvokeAll2() throws Exception {
1289 >        final ExecutorService e = new CustomExecutor(2);
1290 >        final Collection<Callable<String>> emptyCollection
1291 >            = Collections.emptyList();
1292 >        try (PoolCleaner cleaner = cleaner(e)) {
1293 >            List<Future<String>> r =
1294 >                e.invokeAll(emptyCollection, randomTimeout(), randomTimeUnit());
1295              assertTrue(r.isEmpty());
1106        } catch(Exception ex) {
1107            unexpectedException();
1108        } finally {
1109            joinPool(e);
1296          }
1297      }
1298  
1299      /**
1300       * timed invokeAll(c) throws NPE if c has null elements
1301       */
1302 <    public void testTimedInvokeAll3() {
1303 <        ExecutorService e = new CustomExecutor(2);
1304 <        try {
1305 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1302 >    public void testTimedInvokeAll3() throws Exception {
1303 >        final ExecutorService e = new CustomExecutor(2);
1304 >        try (PoolCleaner cleaner = cleaner(e)) {
1305 >            List<Callable<String>> l = new ArrayList<>();
1306              l.add(new StringTask());
1307              l.add(null);
1308 <            e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1309 <        } catch (NullPointerException success) {
1310 <        } catch(Exception ex) {
1311 <            unexpectedException();
1126 <        } finally {
1127 <            joinPool(e);
1308 >            try {
1309 >                e.invokeAll(l, randomTimeout(), randomTimeUnit());
1310 >                shouldThrow();
1311 >            } catch (NullPointerException success) {}
1312          }
1313      }
1314  
1315      /**
1316       * get of element of invokeAll(c) throws exception on failed task
1317       */
1318 <    public void testTimedInvokeAll4() {
1319 <        ExecutorService e = new CustomExecutor(2);
1320 <        try {
1321 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1322 <            l.add(new NPETask());
1323 <            List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1324 <            assertEquals(1, result.size());
1325 <            for (Iterator<Future<String>> it = result.iterator(); it.hasNext();)
1326 <                it.next().get();
1327 <        } catch(ExecutionException success) {
1328 <        } catch(Exception ex) {
1329 <            unexpectedException();
1330 <        } finally {
1331 <            joinPool(e);
1318 >    public void testTimedInvokeAll4() throws Exception {
1319 >        final ExecutorService e = new CustomExecutor(2);
1320 >        final Collection<Callable<String>> c = new ArrayList<>();
1321 >        c.add(new NPETask());
1322 >        try (PoolCleaner cleaner = cleaner(e)) {
1323 >            List<Future<String>> futures =
1324 >                e.invokeAll(c, LONG_DELAY_MS, MILLISECONDS);
1325 >            assertEquals(1, futures.size());
1326 >            try {
1327 >                futures.get(0).get();
1328 >                shouldThrow();
1329 >            } catch (ExecutionException success) {
1330 >                assertTrue(success.getCause() instanceof NullPointerException);
1331 >            }
1332          }
1333      }
1334  
1335      /**
1336       * timed invokeAll(c) returns results of all completed tasks
1337       */
1338 <    public void testTimedInvokeAll5() {
1339 <        ExecutorService e = new CustomExecutor(2);
1340 <        try {
1341 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1338 >    public void testTimedInvokeAll5() throws Exception {
1339 >        final ExecutorService e = new CustomExecutor(2);
1340 >        try (PoolCleaner cleaner = cleaner(e)) {
1341 >            List<Callable<String>> l = new ArrayList<>();
1342              l.add(new StringTask());
1343              l.add(new StringTask());
1344 <            List<Future<String>> result = e.invokeAll(l, MEDIUM_DELAY_MS, TimeUnit.MILLISECONDS);
1345 <            assertEquals(2, result.size());
1346 <            for (Iterator<Future<String>> it = result.iterator(); it.hasNext();)
1347 <                assertSame(TEST_STRING, it.next().get());
1348 <        } catch (ExecutionException success) {
1165 <        } catch(Exception ex) {
1166 <            unexpectedException();
1167 <        } finally {
1168 <            joinPool(e);
1344 >            List<Future<String>> futures =
1345 >                e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
1346 >            assertEquals(2, futures.size());
1347 >            for (Future<String> future : futures)
1348 >                assertSame(TEST_STRING, future.get());
1349          }
1350      }
1351  
1352      /**
1353       * timed invokeAll(c) cancels tasks not completed by timeout
1354       */
1355 <    public void testTimedInvokeAll6() {
1356 <        ExecutorService e = new CustomExecutor(2);
1357 <        try {
1358 <            ArrayList<Callable<String>> l = new ArrayList<Callable<String>>();
1359 <            l.add(new StringTask());
1360 <            l.add(Executors.callable(new MediumPossiblyInterruptedRunnable(), TEST_STRING));
1361 <            l.add(new StringTask());
1362 <            List<Future<String>> result = e.invokeAll(l, SHORT_DELAY_MS, TimeUnit.MILLISECONDS);
1363 <            assertEquals(3, result.size());
1364 <            Iterator<Future<String>> it = result.iterator();
1365 <            Future<String> f1 = it.next();
1366 <            Future<String> f2 = it.next();
1367 <            Future<String> f3 = it.next();
1368 <            assertTrue(f1.isDone());
1369 <            assertTrue(f2.isDone());
1370 <            assertTrue(f3.isDone());
1371 <            assertFalse(f1.isCancelled());
1372 <            assertTrue(f2.isCancelled());
1373 <        } catch(Exception ex) {
1374 <            unexpectedException();
1375 <        } finally {
1376 <            joinPool(e);
1355 >    public void testTimedInvokeAll6() throws Exception {
1356 >        for (long timeout = timeoutMillis();;) {
1357 >            final CountDownLatch done = new CountDownLatch(1);
1358 >            final Callable<String> waiter = new CheckedCallable<String>() {
1359 >                public String realCall() {
1360 >                    try { done.await(LONG_DELAY_MS, MILLISECONDS); }
1361 >                    catch (InterruptedException ok) {}
1362 >                    return "1"; }};
1363 >            final ExecutorService p = new CustomExecutor(2);
1364 >            try (PoolCleaner cleaner = cleaner(p, done)) {
1365 >                List<Callable<String>> tasks = new ArrayList<>();
1366 >                tasks.add(new StringTask("0"));
1367 >                tasks.add(waiter);
1368 >                tasks.add(new StringTask("2"));
1369 >                long startTime = System.nanoTime();
1370 >                List<Future<String>> futures =
1371 >                    p.invokeAll(tasks, timeout, MILLISECONDS);
1372 >                assertEquals(tasks.size(), futures.size());
1373 >                assertTrue(millisElapsedSince(startTime) >= timeout);
1374 >                for (Future future : futures)
1375 >                    assertTrue(future.isDone());
1376 >                assertTrue(futures.get(1).isCancelled());
1377 >                try {
1378 >                    assertEquals("0", futures.get(0).get());
1379 >                    assertEquals("2", futures.get(2).get());
1380 >                    break;
1381 >                } catch (CancellationException retryWithLongerTimeout) {
1382 >                    timeout *= 2;
1383 >                    if (timeout >= LONG_DELAY_MS / 2)
1384 >                        fail("expected exactly one task to be cancelled");
1385 >                }
1386 >            }
1387          }
1388      }
1389  
1200
1390   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines