1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 */
22
23/*
24 * This file is available under and governed by the GNU General Public
25 * License version 2 only, as published by the Free Software Foundation.
26 * However, the following notice accompanied the original version of this
27 * file:
28 *
29 * Written by Doug Lea with assistance from members of JCP JSR-166
30 * Expert Group and released to the public domain, as explained at
31 * http://creativecommons.org/publicdomain/zero/1.0/
32 * Other contributors include Andrew Wright, Jeffrey Hayes,
33 * Pat Fisher, Mike Judd.
34 */
35
36import static java.util.concurrent.TimeUnit.MILLISECONDS;
37import static java.util.concurrent.TimeUnit.SECONDS;
38
39import java.util.ArrayList;
40import java.util.Collection;
41import java.util.Collections;
42import java.util.List;
43import java.util.concurrent.ArrayBlockingQueue;
44import java.util.concurrent.BlockingQueue;
45import java.util.concurrent.Callable;
46import java.util.concurrent.CancellationException;
47import java.util.concurrent.CountDownLatch;
48import java.util.concurrent.ExecutionException;
49import java.util.concurrent.ExecutorService;
50import java.util.concurrent.Future;
51import java.util.concurrent.FutureTask;
52import java.util.concurrent.LinkedBlockingQueue;
53import java.util.concurrent.RejectedExecutionHandler;
54import java.util.concurrent.RunnableFuture;
55import java.util.concurrent.SynchronousQueue;
56import java.util.concurrent.ThreadFactory;
57import java.util.concurrent.ThreadLocalRandom;
58import java.util.concurrent.ThreadPoolExecutor;
59import java.util.concurrent.TimeoutException;
60import java.util.concurrent.TimeUnit;
61import java.util.concurrent.atomic.AtomicInteger;
62import java.util.concurrent.locks.Condition;
63import java.util.concurrent.locks.ReentrantLock;
64
65import junit.framework.Test;
66import junit.framework.TestSuite;
67
68public class ThreadPoolExecutorSubclassTest extends JSR166TestCase {
69    public static void main(String[] args) {
70        main(suite(), args);
71    }
72    public static Test suite() {
73        return new TestSuite(ThreadPoolExecutorSubclassTest.class);
74    }
75
76    static class CustomTask<V> implements RunnableFuture<V> {
77        final Callable<V> callable;
78        final ReentrantLock lock = new ReentrantLock();
79        final Condition cond = lock.newCondition();
80        boolean done;
81        boolean cancelled;
82        V result;
83        Thread thread;
84        Exception exception;
85        CustomTask(Callable<V> c) {
86            if (c == null) throw new NullPointerException();
87            callable = c;
88        }
89        CustomTask(final Runnable r, final V res) {
90            if (r == null) throw new NullPointerException();
91            callable = new Callable<V>() {
92                public V call() throws Exception { r.run(); return res; }};
93        }
94        public boolean isDone() {
95            lock.lock(); try { return done; } finally { lock.unlock() ; }
96        }
97        public boolean isCancelled() {
98            lock.lock(); try { return cancelled; } finally { lock.unlock() ; }
99        }
100        public boolean cancel(boolean mayInterrupt) {
101            lock.lock();
102            try {
103                if (!done) {
104                    cancelled = true;
105                    done = true;
106                    if (mayInterrupt && thread != null)
107                        thread.interrupt();
108                    return true;
109                }
110                return false;
111            }
112            finally { lock.unlock() ; }
113        }
114        public void run() {
115            lock.lock();
116            try {
117                if (done)
118                    return;
119                thread = Thread.currentThread();
120            }
121            finally { lock.unlock() ; }
122            V v = null;
123            Exception e = null;
124            try {
125                v = callable.call();
126            }
127            catch (Exception ex) {
128                e = ex;
129            }
130            lock.lock();
131            try {
132                if (!done) {
133                    result = v;
134                    exception = e;
135                    done = true;
136                    thread = null;
137                    cond.signalAll();
138                }
139            }
140            finally { lock.unlock(); }
141        }
142        public V get() throws InterruptedException, ExecutionException {
143            lock.lock();
144            try {
145                while (!done)
146                    cond.await();
147                if (cancelled)
148                    throw new CancellationException();
149                if (exception != null)
150                    throw new ExecutionException(exception);
151                return result;
152            }
153            finally { lock.unlock(); }
154        }
155        public V get(long timeout, TimeUnit unit)
156            throws InterruptedException, ExecutionException, TimeoutException {
157            long nanos = unit.toNanos(timeout);
158            lock.lock();
159            try {
160                while (!done) {
161                    if (nanos <= 0L)
162                        throw new TimeoutException();
163                    nanos = cond.awaitNanos(nanos);
164                }
165                if (cancelled)
166                    throw new CancellationException();
167                if (exception != null)
168                    throw new ExecutionException(exception);
169                return result;
170            }
171            finally { lock.unlock(); }
172        }
173    }
174
175    static class CustomTPE extends ThreadPoolExecutor {
176        protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
177            return new CustomTask<V>(c);
178        }
179        protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
180            return new CustomTask<V>(r, v);
181        }
182
183        CustomTPE(int corePoolSize,
184                  int maximumPoolSize,
185                  long keepAliveTime,
186                  TimeUnit unit,
187                  BlockingQueue<Runnable> workQueue) {
188            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
189                  workQueue);
190        }
191        CustomTPE(int corePoolSize,
192                  int maximumPoolSize,
193                  long keepAliveTime,
194                  TimeUnit unit,
195                  BlockingQueue<Runnable> workQueue,
196                  ThreadFactory threadFactory) {
197        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
198             threadFactory);
199        }
200
201        CustomTPE(int corePoolSize,
202                  int maximumPoolSize,
203                  long keepAliveTime,
204                  TimeUnit unit,
205                  BlockingQueue<Runnable> workQueue,
206                  RejectedExecutionHandler handler) {
207        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
208              handler);
209        }
210        CustomTPE(int corePoolSize,
211                  int maximumPoolSize,
212                  long keepAliveTime,
213                  TimeUnit unit,
214                  BlockingQueue<Runnable> workQueue,
215                  ThreadFactory threadFactory,
216                  RejectedExecutionHandler handler) {
217            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
218              workQueue, threadFactory, handler);
219        }
220
221        final CountDownLatch beforeCalled = new CountDownLatch(1);
222        final CountDownLatch afterCalled = new CountDownLatch(1);
223        final CountDownLatch terminatedCalled = new CountDownLatch(1);
224
225        public CustomTPE() {
226            super(1, 1, LONG_DELAY_MS, MILLISECONDS, new SynchronousQueue<Runnable>());
227        }
228        protected void beforeExecute(Thread t, Runnable r) {
229            beforeCalled.countDown();
230        }
231        protected void afterExecute(Runnable r, Throwable t) {
232            afterCalled.countDown();
233        }
234        protected void terminated() {
235            terminatedCalled.countDown();
236        }
237
238        public boolean beforeCalled() {
239            return beforeCalled.getCount() == 0;
240        }
241        public boolean afterCalled() {
242            return afterCalled.getCount() == 0;
243        }
244        public boolean terminatedCalled() {
245            return terminatedCalled.getCount() == 0;
246        }
247    }
248
249    static class FailingThreadFactory implements ThreadFactory {
250        int calls = 0;
251        public Thread newThread(Runnable r) {
252            if (++calls > 1) return null;
253            return new Thread(r);
254        }
255    }
256
257    /**
258     * execute successfully executes a runnable
259     */
260    public void testExecute() throws InterruptedException {
261        final ThreadPoolExecutor p =
262            new CustomTPE(1, 1,
263                          2 * LONG_DELAY_MS, MILLISECONDS,
264                          new ArrayBlockingQueue<Runnable>(10));
265        try (PoolCleaner cleaner = cleaner(p)) {
266            final CountDownLatch done = new CountDownLatch(1);
267            final Runnable task = new CheckedRunnable() {
268                public void realRun() { done.countDown(); }};
269            p.execute(task);
270            await(done);
271        }
272    }
273
274    /**
275     * getActiveCount increases but doesn't overestimate, when a
276     * thread becomes active
277     */
278    public void testGetActiveCount() throws InterruptedException {
279        final CountDownLatch done = new CountDownLatch(1);
280        final ThreadPoolExecutor p =
281            new CustomTPE(2, 2,
282                          LONG_DELAY_MS, MILLISECONDS,
283                          new ArrayBlockingQueue<Runnable>(10));
284        try (PoolCleaner cleaner = cleaner(p, done)) {
285            final CountDownLatch threadStarted = new CountDownLatch(1);
286            assertEquals(0, p.getActiveCount());
287            p.execute(new CheckedRunnable() {
288                public void realRun() throws InterruptedException {
289                    threadStarted.countDown();
290                    assertEquals(1, p.getActiveCount());
291                    await(done);
292                }});
293            await(threadStarted);
294            assertEquals(1, p.getActiveCount());
295        }
296    }
297
298    /**
299     * prestartCoreThread starts a thread if under corePoolSize, else doesn't
300     */
301    public void testPrestartCoreThread() {
302        final ThreadPoolExecutor p =
303            new CustomTPE(2, 6,
304                          LONG_DELAY_MS, MILLISECONDS,
305                          new ArrayBlockingQueue<Runnable>(10));
306        try (PoolCleaner cleaner = cleaner(p)) {
307            assertEquals(0, p.getPoolSize());
308            assertTrue(p.prestartCoreThread());
309            assertEquals(1, p.getPoolSize());
310            assertTrue(p.prestartCoreThread());
311            assertEquals(2, p.getPoolSize());
312            assertFalse(p.prestartCoreThread());
313            assertEquals(2, p.getPoolSize());
314            p.setCorePoolSize(4);
315            assertTrue(p.prestartCoreThread());
316            assertEquals(3, p.getPoolSize());
317            assertTrue(p.prestartCoreThread());
318            assertEquals(4, p.getPoolSize());
319            assertFalse(p.prestartCoreThread());
320            assertEquals(4, p.getPoolSize());
321        }
322    }
323
324    /**
325     * prestartAllCoreThreads starts all corePoolSize threads
326     */
327    public void testPrestartAllCoreThreads() {
328        final ThreadPoolExecutor p =
329            new CustomTPE(2, 6,
330                          LONG_DELAY_MS, MILLISECONDS,
331                          new ArrayBlockingQueue<Runnable>(10));
332        try (PoolCleaner cleaner = cleaner(p)) {
333            assertEquals(0, p.getPoolSize());
334            p.prestartAllCoreThreads();
335            assertEquals(2, p.getPoolSize());
336            p.prestartAllCoreThreads();
337            assertEquals(2, p.getPoolSize());
338            p.setCorePoolSize(4);
339            p.prestartAllCoreThreads();
340            assertEquals(4, p.getPoolSize());
341            p.prestartAllCoreThreads();
342            assertEquals(4, p.getPoolSize());
343        }
344    }
345
346    /**
347     * getCompletedTaskCount increases, but doesn't overestimate,
348     * when tasks complete
349     */
350    public void testGetCompletedTaskCount() throws InterruptedException {
351        final ThreadPoolExecutor p =
352            new CustomTPE(2, 2,
353                          LONG_DELAY_MS, MILLISECONDS,
354                          new ArrayBlockingQueue<Runnable>(10));
355        try (PoolCleaner cleaner = cleaner(p)) {
356            final CountDownLatch threadStarted = new CountDownLatch(1);
357            final CountDownLatch threadProceed = new CountDownLatch(1);
358            final CountDownLatch threadDone = new CountDownLatch(1);
359            assertEquals(0, p.getCompletedTaskCount());
360            p.execute(new CheckedRunnable() {
361                public void realRun() throws InterruptedException {
362                    threadStarted.countDown();
363                    assertEquals(0, p.getCompletedTaskCount());
364                    await(threadProceed);
365                    threadDone.countDown();
366                }});
367            await(threadStarted);
368            assertEquals(0, p.getCompletedTaskCount());
369            threadProceed.countDown();
370            await(threadDone);
371            long startTime = System.nanoTime();
372            while (p.getCompletedTaskCount() != 1) {
373                if (millisElapsedSince(startTime) > LONG_DELAY_MS)
374                    fail("timed out");
375                Thread.yield();
376            }
377        }
378    }
379
380    /**
381     * getCorePoolSize returns size given in constructor if not otherwise set
382     */
383    public void testGetCorePoolSize() {
384        final ThreadPoolExecutor p =
385            new CustomTPE(1, 1,
386                          LONG_DELAY_MS, MILLISECONDS,
387                          new ArrayBlockingQueue<Runnable>(10));
388        try (PoolCleaner cleaner = cleaner(p)) {
389            assertEquals(1, p.getCorePoolSize());
390        }
391    }
392
393    /**
394     * getKeepAliveTime returns value given in constructor if not otherwise set
395     */
396    public void testGetKeepAliveTime() {
397        final ThreadPoolExecutor p =
398            new CustomTPE(2, 2,
399                          1000, MILLISECONDS,
400                          new ArrayBlockingQueue<Runnable>(10));
401        try (PoolCleaner cleaner = cleaner(p)) {
402            assertEquals(1, p.getKeepAliveTime(SECONDS));
403        }
404    }
405
406    /**
407     * getThreadFactory returns factory in constructor if not set
408     */
409    public void testGetThreadFactory() {
410        final ThreadFactory threadFactory = new SimpleThreadFactory();
411        final ThreadPoolExecutor p =
412            new CustomTPE(1, 2,
413                          LONG_DELAY_MS, MILLISECONDS,
414                          new ArrayBlockingQueue<Runnable>(10),
415                          threadFactory,
416                          new NoOpREHandler());
417        try (PoolCleaner cleaner = cleaner(p)) {
418            assertSame(threadFactory, p.getThreadFactory());
419        }
420    }
421
422    /**
423     * setThreadFactory sets the thread factory returned by getThreadFactory
424     */
425    public void testSetThreadFactory() {
426        final ThreadPoolExecutor p =
427            new CustomTPE(1, 2,
428                          LONG_DELAY_MS, MILLISECONDS,
429                          new ArrayBlockingQueue<Runnable>(10));
430        try (PoolCleaner cleaner = cleaner(p)) {
431            ThreadFactory threadFactory = new SimpleThreadFactory();
432            p.setThreadFactory(threadFactory);
433            assertSame(threadFactory, p.getThreadFactory());
434        }
435    }
436
437    /**
438     * setThreadFactory(null) throws NPE
439     */
440    public void testSetThreadFactoryNull() {
441        final ThreadPoolExecutor p =
442            new CustomTPE(1, 2,
443                          LONG_DELAY_MS, MILLISECONDS,
444                          new ArrayBlockingQueue<Runnable>(10));
445        try (PoolCleaner cleaner = cleaner(p)) {
446            try {
447                p.setThreadFactory(null);
448                shouldThrow();
449            } catch (NullPointerException success) {}
450        }
451    }
452
453    /**
454     * getRejectedExecutionHandler returns handler in constructor if not set
455     */
456    public void testGetRejectedExecutionHandler() {
457        final RejectedExecutionHandler handler = new NoOpREHandler();
458        final ThreadPoolExecutor p =
459            new CustomTPE(1, 2,
460                          LONG_DELAY_MS, MILLISECONDS,
461                          new ArrayBlockingQueue<Runnable>(10),
462                          handler);
463        try (PoolCleaner cleaner = cleaner(p)) {
464            assertSame(handler, p.getRejectedExecutionHandler());
465        }
466    }
467
468    /**
469     * setRejectedExecutionHandler sets the handler returned by
470     * getRejectedExecutionHandler
471     */
472    public void testSetRejectedExecutionHandler() {
473        final ThreadPoolExecutor p =
474            new CustomTPE(1, 2,
475                          LONG_DELAY_MS, MILLISECONDS,
476                          new ArrayBlockingQueue<Runnable>(10));
477        try (PoolCleaner cleaner = cleaner(p)) {
478            RejectedExecutionHandler handler = new NoOpREHandler();
479            p.setRejectedExecutionHandler(handler);
480            assertSame(handler, p.getRejectedExecutionHandler());
481        }
482    }
483
484    /**
485     * setRejectedExecutionHandler(null) throws NPE
486     */
487    public void testSetRejectedExecutionHandlerNull() {
488        final ThreadPoolExecutor p =
489            new CustomTPE(1, 2,
490                          LONG_DELAY_MS, MILLISECONDS,
491                          new ArrayBlockingQueue<Runnable>(10));
492        try (PoolCleaner cleaner = cleaner(p)) {
493            try {
494                p.setRejectedExecutionHandler(null);
495                shouldThrow();
496            } catch (NullPointerException success) {}
497        }
498    }
499
500    /**
501     * getLargestPoolSize increases, but doesn't overestimate, when
502     * multiple threads active
503     */
504    public void testGetLargestPoolSize() throws InterruptedException {
505        final int THREADS = 3;
506        final CountDownLatch done = new CountDownLatch(1);
507        final ThreadPoolExecutor p =
508            new CustomTPE(THREADS, THREADS,
509                          LONG_DELAY_MS, MILLISECONDS,
510                          new ArrayBlockingQueue<Runnable>(10));
511        try (PoolCleaner cleaner = cleaner(p, done)) {
512            assertEquals(0, p.getLargestPoolSize());
513            final CountDownLatch threadsStarted = new CountDownLatch(THREADS);
514            for (int i = 0; i < THREADS; i++)
515                p.execute(new CheckedRunnable() {
516                    public void realRun() throws InterruptedException {
517                        threadsStarted.countDown();
518                        await(done);
519                        assertEquals(THREADS, p.getLargestPoolSize());
520                    }});
521            await(threadsStarted);
522            assertEquals(THREADS, p.getLargestPoolSize());
523        }
524        assertEquals(THREADS, p.getLargestPoolSize());
525    }
526
527    /**
528     * getMaximumPoolSize returns value given in constructor if not
529     * otherwise set
530     */
531    public void testGetMaximumPoolSize() {
532        final ThreadPoolExecutor p =
533            new CustomTPE(2, 3,
534                          LONG_DELAY_MS, MILLISECONDS,
535                          new ArrayBlockingQueue<Runnable>(10));
536        try (PoolCleaner cleaner = cleaner(p)) {
537            assertEquals(3, p.getMaximumPoolSize());
538            p.setMaximumPoolSize(5);
539            assertEquals(5, p.getMaximumPoolSize());
540            p.setMaximumPoolSize(4);
541            assertEquals(4, p.getMaximumPoolSize());
542        }
543    }
544
545    /**
546     * getPoolSize increases, but doesn't overestimate, when threads
547     * become active
548     */
549    public void testGetPoolSize() throws InterruptedException {
550        final CountDownLatch done = new CountDownLatch(1);
551        final ThreadPoolExecutor p =
552            new CustomTPE(1, 1,
553                          LONG_DELAY_MS, MILLISECONDS,
554                          new ArrayBlockingQueue<Runnable>(10));
555        try (PoolCleaner cleaner = cleaner(p, done)) {
556            assertEquals(0, p.getPoolSize());
557            final CountDownLatch threadStarted = new CountDownLatch(1);
558            p.execute(new CheckedRunnable() {
559                public void realRun() throws InterruptedException {
560                    threadStarted.countDown();
561                    assertEquals(1, p.getPoolSize());
562                    await(done);
563                }});
564            await(threadStarted);
565            assertEquals(1, p.getPoolSize());
566        }
567    }
568
569    /**
570     * getTaskCount increases, but doesn't overestimate, when tasks submitted
571     */
572    public void testGetTaskCount() throws InterruptedException {
573        final int TASKS = 3;
574        final CountDownLatch done = new CountDownLatch(1);
575        final ThreadPoolExecutor p =
576            new CustomTPE(1, 1,
577                          LONG_DELAY_MS, MILLISECONDS,
578                          new ArrayBlockingQueue<Runnable>(10));
579        try (PoolCleaner cleaner = cleaner(p, done)) {
580            final CountDownLatch threadStarted = new CountDownLatch(1);
581            assertEquals(0, p.getTaskCount());
582            assertEquals(0, p.getCompletedTaskCount());
583            p.execute(new CheckedRunnable() {
584                public void realRun() throws InterruptedException {
585                    threadStarted.countDown();
586                    await(done);
587                }});
588            await(threadStarted);
589            assertEquals(1, p.getTaskCount());
590            assertEquals(0, p.getCompletedTaskCount());
591            for (int i = 0; i < TASKS; i++) {
592                assertEquals(1 + i, p.getTaskCount());
593                p.execute(new CheckedRunnable() {
594                    public void realRun() throws InterruptedException {
595                        threadStarted.countDown();
596                        assertEquals(1 + TASKS, p.getTaskCount());
597                        await(done);
598                    }});
599            }
600            assertEquals(1 + TASKS, p.getTaskCount());
601            assertEquals(0, p.getCompletedTaskCount());
602        }
603        assertEquals(1 + TASKS, p.getTaskCount());
604        assertEquals(1 + TASKS, p.getCompletedTaskCount());
605    }
606
607    /**
608     * isShutdown is false before shutdown, true after
609     */
610    public void testIsShutdown() {
611        final ThreadPoolExecutor p =
612            new CustomTPE(1, 1,
613                          LONG_DELAY_MS, MILLISECONDS,
614                          new ArrayBlockingQueue<Runnable>(10));
615        try (PoolCleaner cleaner = cleaner(p)) {
616            assertFalse(p.isShutdown());
617            try { p.shutdown(); } catch (SecurityException ok) { return; }
618            assertTrue(p.isShutdown());
619        }
620    }
621
622    /**
623     * isTerminated is false before termination, true after
624     */
625    public void testIsTerminated() throws InterruptedException {
626        final ThreadPoolExecutor p =
627            new CustomTPE(1, 1,
628                          LONG_DELAY_MS, MILLISECONDS,
629                          new ArrayBlockingQueue<Runnable>(10));
630        try (PoolCleaner cleaner = cleaner(p)) {
631            final CountDownLatch threadStarted = new CountDownLatch(1);
632            final CountDownLatch done = new CountDownLatch(1);
633            assertFalse(p.isTerminating());
634            p.execute(new CheckedRunnable() {
635                public void realRun() throws InterruptedException {
636                    assertFalse(p.isTerminating());
637                    threadStarted.countDown();
638                    await(done);
639                }});
640            await(threadStarted);
641            assertFalse(p.isTerminating());
642            done.countDown();
643            try { p.shutdown(); } catch (SecurityException ok) { return; }
644            assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
645            assertTrue(p.isTerminated());
646            assertFalse(p.isTerminating());
647        }
648    }
649
650    /**
651     * isTerminating is not true when running or when terminated
652     */
653    public void testIsTerminating() throws InterruptedException {
654        final ThreadPoolExecutor p =
655            new CustomTPE(1, 1,
656                          LONG_DELAY_MS, MILLISECONDS,
657                          new ArrayBlockingQueue<Runnable>(10));
658        try (PoolCleaner cleaner = cleaner(p)) {
659            final CountDownLatch threadStarted = new CountDownLatch(1);
660            final CountDownLatch done = new CountDownLatch(1);
661            assertFalse(p.isTerminating());
662            p.execute(new CheckedRunnable() {
663                public void realRun() throws InterruptedException {
664                    assertFalse(p.isTerminating());
665                    threadStarted.countDown();
666                    await(done);
667                }});
668            await(threadStarted);
669            assertFalse(p.isTerminating());
670            done.countDown();
671            try { p.shutdown(); } catch (SecurityException ok) { return; }
672            assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
673            assertTrue(p.isTerminated());
674            assertFalse(p.isTerminating());
675        }
676    }
677
678    /**
679     * getQueue returns the work queue, which contains queued tasks
680     */
681    public void testGetQueue() throws InterruptedException {
682        final CountDownLatch done = new CountDownLatch(1);
683        final BlockingQueue<Runnable> q = new ArrayBlockingQueue<>(10);
684        final ThreadPoolExecutor p =
685            new CustomTPE(1, 1,
686                          LONG_DELAY_MS, MILLISECONDS,
687                          q);
688        try (PoolCleaner cleaner = cleaner(p, done)) {
689            final CountDownLatch threadStarted = new CountDownLatch(1);
690            FutureTask[] tasks = new FutureTask[5];
691            for (int i = 0; i < tasks.length; i++) {
692                Callable<Boolean> task = new CheckedCallable<Boolean>() {
693                    public Boolean realCall() throws InterruptedException {
694                        threadStarted.countDown();
695                        assertSame(q, p.getQueue());
696                        await(done);
697                        return Boolean.TRUE;
698                    }};
699                tasks[i] = new FutureTask(task);
700                p.execute(tasks[i]);
701            }
702            await(threadStarted);
703            assertSame(q, p.getQueue());
704            assertFalse(q.contains(tasks[0]));
705            assertTrue(q.contains(tasks[tasks.length - 1]));
706            assertEquals(tasks.length - 1, q.size());
707        }
708    }
709
710    /**
711     * remove(task) removes queued task, and fails to remove active task
712     */
713    public void testRemove() throws InterruptedException {
714        final CountDownLatch done = new CountDownLatch(1);
715        BlockingQueue<Runnable> q = new ArrayBlockingQueue<>(10);
716        final ThreadPoolExecutor p =
717            new CustomTPE(1, 1,
718                          LONG_DELAY_MS, MILLISECONDS,
719                          q);
720        try (PoolCleaner cleaner = cleaner(p, done)) {
721            Runnable[] tasks = new Runnable[6];
722            final CountDownLatch threadStarted = new CountDownLatch(1);
723            for (int i = 0; i < tasks.length; i++) {
724                tasks[i] = new CheckedRunnable() {
725                    public void realRun() throws InterruptedException {
726                        threadStarted.countDown();
727                        await(done);
728                    }};
729                p.execute(tasks[i]);
730            }
731            await(threadStarted);
732            assertFalse(p.remove(tasks[0]));
733            assertTrue(q.contains(tasks[4]));
734            assertTrue(q.contains(tasks[3]));
735            assertTrue(p.remove(tasks[4]));
736            assertFalse(p.remove(tasks[4]));
737            assertFalse(q.contains(tasks[4]));
738            assertTrue(q.contains(tasks[3]));
739            assertTrue(p.remove(tasks[3]));
740            assertFalse(q.contains(tasks[3]));
741        }
742    }
743
744    /**
745     * purge removes cancelled tasks from the queue
746     */
747    public void testPurge() throws InterruptedException {
748        final CountDownLatch threadStarted = new CountDownLatch(1);
749        final CountDownLatch done = new CountDownLatch(1);
750        final BlockingQueue<Runnable> q = new ArrayBlockingQueue<>(10);
751        final ThreadPoolExecutor p =
752            new CustomTPE(1, 1,
753                          LONG_DELAY_MS, MILLISECONDS,
754                          q);
755        try (PoolCleaner cleaner = cleaner(p, done)) {
756            FutureTask[] tasks = new FutureTask[5];
757            for (int i = 0; i < tasks.length; i++) {
758                Callable<Boolean> task = new CheckedCallable<Boolean>() {
759                    public Boolean realCall() throws InterruptedException {
760                        threadStarted.countDown();
761                        await(done);
762                        return Boolean.TRUE;
763                    }};
764                tasks[i] = new FutureTask(task);
765                p.execute(tasks[i]);
766            }
767            await(threadStarted);
768            assertEquals(tasks.length, p.getTaskCount());
769            assertEquals(tasks.length - 1, q.size());
770            assertEquals(1L, p.getActiveCount());
771            assertEquals(0L, p.getCompletedTaskCount());
772            tasks[4].cancel(true);
773            tasks[3].cancel(false);
774            p.purge();
775            assertEquals(tasks.length - 3, q.size());
776            assertEquals(tasks.length - 2, p.getTaskCount());
777            p.purge();         // Nothing to do
778            assertEquals(tasks.length - 3, q.size());
779            assertEquals(tasks.length - 2, p.getTaskCount());
780        }
781    }
782
783    /**
784     * shutdownNow returns a list containing tasks that were not run,
785     * and those tasks are drained from the queue
786     */
787    public void testShutdownNow() throws InterruptedException {
788        final int poolSize = 2;
789        final int count = 5;
790        final AtomicInteger ran = new AtomicInteger(0);
791        final ThreadPoolExecutor p =
792            new CustomTPE(poolSize, poolSize,
793                          LONG_DELAY_MS, MILLISECONDS,
794                          new ArrayBlockingQueue<Runnable>(10));
795        final CountDownLatch threadsStarted = new CountDownLatch(poolSize);
796        Runnable waiter = new CheckedRunnable() { public void realRun() {
797            threadsStarted.countDown();
798            try {
799                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
800            } catch (InterruptedException success) {}
801            ran.getAndIncrement();
802        }};
803        for (int i = 0; i < count; i++)
804            p.execute(waiter);
805        await(threadsStarted);
806        assertEquals(poolSize, p.getActiveCount());
807        assertEquals(0, p.getCompletedTaskCount());
808        final List<Runnable> queuedTasks;
809        try {
810            queuedTasks = p.shutdownNow();
811        } catch (SecurityException ok) {
812            return; // Allowed in case test doesn't have privs
813        }
814        assertTrue(p.isShutdown());
815        assertTrue(p.getQueue().isEmpty());
816        assertEquals(count - poolSize, queuedTasks.size());
817        assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
818        assertTrue(p.isTerminated());
819        assertEquals(poolSize, ran.get());
820        assertEquals(poolSize, p.getCompletedTaskCount());
821    }
822
823    // Exception Tests
824
825    /**
826     * Constructor throws if corePoolSize argument is less than zero
827     */
828    public void testConstructor1() {
829        try {
830            new CustomTPE(-1, 1, 1L, SECONDS,
831                          new ArrayBlockingQueue<Runnable>(10));
832            shouldThrow();
833        } catch (IllegalArgumentException success) {}
834    }
835
836    /**
837     * Constructor throws if maximumPoolSize is less than zero
838     */
839    public void testConstructor2() {
840        try {
841            new CustomTPE(1, -1, 1L, SECONDS,
842                          new ArrayBlockingQueue<Runnable>(10));
843            shouldThrow();
844        } catch (IllegalArgumentException success) {}
845    }
846
847    /**
848     * Constructor throws if maximumPoolSize is equal to zero
849     */
850    public void testConstructor3() {
851        try {
852            new CustomTPE(1, 0, 1L, SECONDS,
853                          new ArrayBlockingQueue<Runnable>(10));
854            shouldThrow();
855        } catch (IllegalArgumentException success) {}
856    }
857
858    /**
859     * Constructor throws if keepAliveTime is less than zero
860     */
861    public void testConstructor4() {
862        try {
863            new CustomTPE(1, 2, -1L, SECONDS,
864                          new ArrayBlockingQueue<Runnable>(10));
865            shouldThrow();
866        } catch (IllegalArgumentException success) {}
867    }
868
869    /**
870     * Constructor throws if corePoolSize is greater than the maximumPoolSize
871     */
872    public void testConstructor5() {
873        try {
874            new CustomTPE(2, 1, 1L, SECONDS,
875                          new ArrayBlockingQueue<Runnable>(10));
876            shouldThrow();
877        } catch (IllegalArgumentException success) {}
878    }
879
880    /**
881     * Constructor throws if workQueue is set to null
882     */
883    public void testConstructorNullPointerException() {
884        try {
885            new CustomTPE(1, 2, 1L, SECONDS, null);
886            shouldThrow();
887        } catch (NullPointerException success) {}
888    }
889
890    /**
891     * Constructor throws if corePoolSize argument is less than zero
892     */
893    public void testConstructor6() {
894        try {
895            new CustomTPE(-1, 1, 1L, SECONDS,
896                          new ArrayBlockingQueue<Runnable>(10),
897                          new SimpleThreadFactory());
898            shouldThrow();
899        } catch (IllegalArgumentException success) {}
900    }
901
902    /**
903     * Constructor throws if maximumPoolSize is less than zero
904     */
905    public void testConstructor7() {
906        try {
907            new CustomTPE(1,-1, 1L, SECONDS,
908                          new ArrayBlockingQueue<Runnable>(10),
909                          new SimpleThreadFactory());
910            shouldThrow();
911        } catch (IllegalArgumentException success) {}
912    }
913
914    /**
915     * Constructor throws if maximumPoolSize is equal to zero
916     */
917    public void testConstructor8() {
918        try {
919            new CustomTPE(1, 0, 1L, SECONDS,
920                          new ArrayBlockingQueue<Runnable>(10),
921                          new SimpleThreadFactory());
922            shouldThrow();
923        } catch (IllegalArgumentException success) {}
924    }
925
926    /**
927     * Constructor throws if keepAliveTime is less than zero
928     */
929    public void testConstructor9() {
930        try {
931            new CustomTPE(1, 2, -1L, SECONDS,
932                          new ArrayBlockingQueue<Runnable>(10),
933                          new SimpleThreadFactory());
934            shouldThrow();
935        } catch (IllegalArgumentException success) {}
936    }
937
938    /**
939     * Constructor throws if corePoolSize is greater than the maximumPoolSize
940     */
941    public void testConstructor10() {
942        try {
943            new CustomTPE(2, 1, 1L, SECONDS,
944                          new ArrayBlockingQueue<Runnable>(10),
945                          new SimpleThreadFactory());
946            shouldThrow();
947        } catch (IllegalArgumentException success) {}
948    }
949
950    /**
951     * Constructor throws if workQueue is set to null
952     */
953    public void testConstructorNullPointerException2() {
954        try {
955            new CustomTPE(1, 2, 1L, SECONDS, null, new SimpleThreadFactory());
956            shouldThrow();
957        } catch (NullPointerException success) {}
958    }
959
960    /**
961     * Constructor throws if threadFactory is set to null
962     */
963    public void testConstructorNullPointerException3() {
964        try {
965            new CustomTPE(1, 2, 1L, SECONDS,
966                          new ArrayBlockingQueue<Runnable>(10),
967                          (ThreadFactory) null);
968            shouldThrow();
969        } catch (NullPointerException success) {}
970    }
971
972    /**
973     * Constructor throws if corePoolSize argument is less than zero
974     */
975    public void testConstructor11() {
976        try {
977            new CustomTPE(-1, 1, 1L, SECONDS,
978                          new ArrayBlockingQueue<Runnable>(10),
979                          new NoOpREHandler());
980            shouldThrow();
981        } catch (IllegalArgumentException success) {}
982    }
983
984    /**
985     * Constructor throws if maximumPoolSize is less than zero
986     */
987    public void testConstructor12() {
988        try {
989            new CustomTPE(1, -1, 1L, SECONDS,
990                          new ArrayBlockingQueue<Runnable>(10),
991                          new NoOpREHandler());
992            shouldThrow();
993        } catch (IllegalArgumentException success) {}
994    }
995
996    /**
997     * Constructor throws if maximumPoolSize is equal to zero
998     */
999    public void testConstructor13() {
1000        try {
1001            new CustomTPE(1, 0, 1L, SECONDS,
1002                          new ArrayBlockingQueue<Runnable>(10),
1003                          new NoOpREHandler());
1004            shouldThrow();
1005        } catch (IllegalArgumentException success) {}
1006    }
1007
1008    /**
1009     * Constructor throws if keepAliveTime is less than zero
1010     */
1011    public void testConstructor14() {
1012        try {
1013            new CustomTPE(1, 2, -1L, SECONDS,
1014                          new ArrayBlockingQueue<Runnable>(10),
1015                          new NoOpREHandler());
1016            shouldThrow();
1017        } catch (IllegalArgumentException success) {}
1018    }
1019
1020    /**
1021     * Constructor throws if corePoolSize is greater than the maximumPoolSize
1022     */
1023    public void testConstructor15() {
1024        try {
1025            new CustomTPE(2, 1, 1L, SECONDS,
1026                          new ArrayBlockingQueue<Runnable>(10),
1027                          new NoOpREHandler());
1028            shouldThrow();
1029        } catch (IllegalArgumentException success) {}
1030    }
1031
1032    /**
1033     * Constructor throws if workQueue is set to null
1034     */
1035    public void testConstructorNullPointerException4() {
1036        try {
1037            new CustomTPE(1, 2, 1L, SECONDS,
1038                          null,
1039                          new NoOpREHandler());
1040            shouldThrow();
1041        } catch (NullPointerException success) {}
1042    }
1043
1044    /**
1045     * Constructor throws if handler is set to null
1046     */
1047    public void testConstructorNullPointerException5() {
1048        try {
1049            new CustomTPE(1, 2, 1L, SECONDS,
1050                          new ArrayBlockingQueue<Runnable>(10),
1051                          (RejectedExecutionHandler) null);
1052            shouldThrow();
1053        } catch (NullPointerException success) {}
1054    }
1055
1056    /**
1057     * Constructor throws if corePoolSize argument is less than zero
1058     */
1059    public void testConstructor16() {
1060        try {
1061            new CustomTPE(-1, 1, 1L, SECONDS,
1062                          new ArrayBlockingQueue<Runnable>(10),
1063                          new SimpleThreadFactory(),
1064                          new NoOpREHandler());
1065            shouldThrow();
1066        } catch (IllegalArgumentException success) {}
1067    }
1068
1069    /**
1070     * Constructor throws if maximumPoolSize is less than zero
1071     */
1072    public void testConstructor17() {
1073        try {
1074            new CustomTPE(1, -1, 1L, SECONDS,
1075                          new ArrayBlockingQueue<Runnable>(10),
1076                          new SimpleThreadFactory(),
1077                          new NoOpREHandler());
1078            shouldThrow();
1079        } catch (IllegalArgumentException success) {}
1080    }
1081
1082    /**
1083     * Constructor throws if maximumPoolSize is equal to zero
1084     */
1085    public void testConstructor18() {
1086        try {
1087            new CustomTPE(1, 0, 1L, SECONDS,
1088                          new ArrayBlockingQueue<Runnable>(10),
1089                          new SimpleThreadFactory(),
1090                          new NoOpREHandler());
1091            shouldThrow();
1092        } catch (IllegalArgumentException success) {}
1093    }
1094
1095    /**
1096     * Constructor throws if keepAliveTime is less than zero
1097     */
1098    public void testConstructor19() {
1099        try {
1100            new CustomTPE(1, 2, -1L, SECONDS,
1101                          new ArrayBlockingQueue<Runnable>(10),
1102                          new SimpleThreadFactory(),
1103                          new NoOpREHandler());
1104            shouldThrow();
1105        } catch (IllegalArgumentException success) {}
1106    }
1107
1108    /**
1109     * Constructor throws if corePoolSize is greater than the maximumPoolSize
1110     */
1111    public void testConstructor20() {
1112        try {
1113            new CustomTPE(2, 1, 1L, SECONDS,
1114                          new ArrayBlockingQueue<Runnable>(10),
1115                          new SimpleThreadFactory(),
1116                          new NoOpREHandler());
1117            shouldThrow();
1118        } catch (IllegalArgumentException success) {}
1119    }
1120
1121    /**
1122     * Constructor throws if workQueue is null
1123     */
1124    public void testConstructorNullPointerException6() {
1125        try {
1126            new CustomTPE(1, 2, 1L, SECONDS,
1127                          null,
1128                          new SimpleThreadFactory(),
1129                          new NoOpREHandler());
1130            shouldThrow();
1131        } catch (NullPointerException success) {}
1132    }
1133
1134    /**
1135     * Constructor throws if handler is null
1136     */
1137    public void testConstructorNullPointerException7() {
1138        try {
1139            new CustomTPE(1, 2, 1L, SECONDS,
1140                          new ArrayBlockingQueue<Runnable>(10),
1141                          new SimpleThreadFactory(),
1142                          (RejectedExecutionHandler) null);
1143            shouldThrow();
1144        } catch (NullPointerException success) {}
1145    }
1146
1147    /**
1148     * Constructor throws if ThreadFactory is null
1149     */
1150    public void testConstructorNullPointerException8() {
1151        try {
1152            new CustomTPE(1, 2, 1L, SECONDS,
1153                          new ArrayBlockingQueue<Runnable>(10),
1154                          (ThreadFactory) null,
1155                          new NoOpREHandler());
1156            shouldThrow();
1157        } catch (NullPointerException success) {}
1158    }
1159
1160    /**
1161     * Submitted tasks are rejected when saturated or shutdown
1162     */
1163    public void testSubmittedTasksRejectedWhenSaturatedOrShutdown() throws InterruptedException {
1164        final ThreadPoolExecutor p =
1165            new CustomTPE(1, 1,
1166                          LONG_DELAY_MS, MILLISECONDS,
1167                          new ArrayBlockingQueue<Runnable>(1));
1168        final int saturatedSize = saturatedSize(p);
1169        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
1170        final CountDownLatch threadsStarted = new CountDownLatch(p.getMaximumPoolSize());
1171        final CountDownLatch done = new CountDownLatch(1);
1172        final Runnable r = () -> {
1173            threadsStarted.countDown();
1174            for (;;) {
1175                try {
1176                    done.await();
1177                    return;
1178                } catch (InterruptedException shutdownNowDeliberatelyIgnored) {}
1179            }};
1180        final Callable<Boolean> c = () -> {
1181            threadsStarted.countDown();
1182            for (;;) {
1183                try {
1184                    done.await();
1185                    return Boolean.TRUE;
1186                } catch (InterruptedException shutdownNowDeliberatelyIgnored) {}
1187            }};
1188        final boolean shutdownNow = rnd.nextBoolean();
1189
1190        try (PoolCleaner cleaner = cleaner(p, done)) {
1191            // saturate
1192            for (int i = saturatedSize; i--> 0; ) {
1193                switch (rnd.nextInt(4)) {
1194                case 0: p.execute(r); break;
1195                case 1: assertFalse(p.submit(r).isDone()); break;
1196                case 2: assertFalse(p.submit(r, Boolean.TRUE).isDone()); break;
1197                case 3: assertFalse(p.submit(c).isDone()); break;
1198                }
1199            }
1200
1201            await(threadsStarted);
1202            assertTaskSubmissionsAreRejected(p);
1203
1204            if (shutdownNow)
1205                p.shutdownNow();
1206            else
1207                p.shutdown();
1208            // Pool is shutdown, but not yet terminated
1209            assertTaskSubmissionsAreRejected(p);
1210            assertFalse(p.isTerminated());
1211
1212            done.countDown();   // release blocking tasks
1213            assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
1214
1215            assertTaskSubmissionsAreRejected(p);
1216        }
1217        assertEquals(saturatedSize(p)
1218                     - (shutdownNow ? p.getQueue().remainingCapacity() : 0),
1219                     p.getCompletedTaskCount());
1220    }
1221
1222    /**
1223     * executor using DiscardOldestPolicy drops oldest task if saturated.
1224     */
1225    public void testSaturatedExecute_DiscardOldestPolicy() {
1226        final CountDownLatch done = new CountDownLatch(1);
1227        LatchAwaiter r1 = awaiter(done);
1228        LatchAwaiter r2 = awaiter(done);
1229        LatchAwaiter r3 = awaiter(done);
1230        final ThreadPoolExecutor p =
1231            new CustomTPE(1, 1,
1232                          LONG_DELAY_MS, MILLISECONDS,
1233                          new ArrayBlockingQueue<Runnable>(1),
1234                          new ThreadPoolExecutor.DiscardOldestPolicy());
1235        try (PoolCleaner cleaner = cleaner(p, done)) {
1236            assertEquals(LatchAwaiter.NEW, r1.state);
1237            assertEquals(LatchAwaiter.NEW, r2.state);
1238            assertEquals(LatchAwaiter.NEW, r3.state);
1239            p.execute(r1);
1240            p.execute(r2);
1241            assertTrue(p.getQueue().contains(r2));
1242            p.execute(r3);
1243            assertFalse(p.getQueue().contains(r2));
1244            assertTrue(p.getQueue().contains(r3));
1245        }
1246        assertEquals(LatchAwaiter.DONE, r1.state);
1247        assertEquals(LatchAwaiter.NEW, r2.state);
1248        assertEquals(LatchAwaiter.DONE, r3.state);
1249    }
1250
1251    /**
1252     * execute using DiscardOldestPolicy drops task on shutdown
1253     */
1254    public void testDiscardOldestOnShutdown() {
1255        final ThreadPoolExecutor p =
1256            new CustomTPE(1, 1,
1257                          LONG_DELAY_MS, MILLISECONDS,
1258                          new ArrayBlockingQueue<Runnable>(1),
1259                          new ThreadPoolExecutor.DiscardOldestPolicy());
1260
1261        try { p.shutdown(); } catch (SecurityException ok) { return; }
1262        try (PoolCleaner cleaner = cleaner(p)) {
1263            TrackedNoOpRunnable r = new TrackedNoOpRunnable();
1264            p.execute(r);
1265            assertFalse(r.done);
1266        }
1267    }
1268
1269    /**
1270     * Submitting null tasks throws NullPointerException
1271     */
1272    public void testNullTaskSubmission() {
1273        final ThreadPoolExecutor p =
1274            new CustomTPE(1, 2,
1275                          1L, SECONDS,
1276                          new ArrayBlockingQueue<Runnable>(10));
1277        try (PoolCleaner cleaner = cleaner(p)) {
1278            assertNullTaskSubmissionThrowsNullPointerException(p);
1279        }
1280    }
1281
1282    /**
1283     * setCorePoolSize of negative value throws IllegalArgumentException
1284     */
1285    public void testCorePoolSizeIllegalArgumentException() {
1286        final ThreadPoolExecutor p =
1287            new CustomTPE(1, 2,
1288                          LONG_DELAY_MS, MILLISECONDS,
1289                          new ArrayBlockingQueue<Runnable>(10));
1290        try (PoolCleaner cleaner = cleaner(p)) {
1291            try {
1292                p.setCorePoolSize(-1);
1293                shouldThrow();
1294            } catch (IllegalArgumentException success) {}
1295        }
1296    }
1297
1298    /**
1299     * setMaximumPoolSize(int) throws IllegalArgumentException
1300     * if given a value less the core pool size
1301     */
1302    public void testMaximumPoolSizeIllegalArgumentException() {
1303        final ThreadPoolExecutor p =
1304            new CustomTPE(2, 3,
1305                          LONG_DELAY_MS, MILLISECONDS,
1306                          new ArrayBlockingQueue<Runnable>(10));
1307        try (PoolCleaner cleaner = cleaner(p)) {
1308            try {
1309                p.setMaximumPoolSize(1);
1310                shouldThrow();
1311            } catch (IllegalArgumentException success) {}
1312        }
1313    }
1314
1315    /**
1316     * setMaximumPoolSize throws IllegalArgumentException
1317     * if given a negative value
1318     */
1319    public void testMaximumPoolSizeIllegalArgumentException2() {
1320        final ThreadPoolExecutor p =
1321            new CustomTPE(2, 3,
1322                          LONG_DELAY_MS, MILLISECONDS,
1323                          new ArrayBlockingQueue<Runnable>(10));
1324        try (PoolCleaner cleaner = cleaner(p)) {
1325            try {
1326                p.setMaximumPoolSize(-1);
1327                shouldThrow();
1328            } catch (IllegalArgumentException success) {}
1329        }
1330    }
1331
1332    /**
1333     * setKeepAliveTime throws IllegalArgumentException
1334     * when given a negative value
1335     */
1336    public void testKeepAliveTimeIllegalArgumentException() {
1337        final ThreadPoolExecutor p =
1338            new CustomTPE(2, 3,
1339                          LONG_DELAY_MS, MILLISECONDS,
1340                          new ArrayBlockingQueue<Runnable>(10));
1341        try (PoolCleaner cleaner = cleaner(p)) {
1342            try {
1343                p.setKeepAliveTime(-1, MILLISECONDS);
1344                shouldThrow();
1345            } catch (IllegalArgumentException success) {}
1346        }
1347    }
1348
1349    /**
1350     * terminated() is called on termination
1351     */
1352    public void testTerminated() {
1353        CustomTPE p = new CustomTPE();
1354        try (PoolCleaner cleaner = cleaner(p)) {
1355            try { p.shutdown(); } catch (SecurityException ok) { return; }
1356            assertTrue(p.terminatedCalled());
1357            assertTrue(p.isShutdown());
1358        }
1359    }
1360
1361    /**
1362     * beforeExecute and afterExecute are called when executing task
1363     */
1364    public void testBeforeAfter() throws InterruptedException {
1365        CustomTPE p = new CustomTPE();
1366        try (PoolCleaner cleaner = cleaner(p)) {
1367            final CountDownLatch done = new CountDownLatch(1);
1368            p.execute(new CheckedRunnable() {
1369                public void realRun() {
1370                    done.countDown();
1371                }});
1372            await(p.afterCalled);
1373            assertEquals(0, done.getCount());
1374            assertTrue(p.afterCalled());
1375            assertTrue(p.beforeCalled());
1376        }
1377    }
1378
1379    /**
1380     * completed submit of callable returns result
1381     */
1382    public void testSubmitCallable() throws Exception {
1383        final ExecutorService e =
1384            new CustomTPE(2, 2,
1385                          LONG_DELAY_MS, MILLISECONDS,
1386                          new ArrayBlockingQueue<Runnable>(10));
1387        try (PoolCleaner cleaner = cleaner(e)) {
1388            Future<String> future = e.submit(new StringTask());
1389            String result = future.get();
1390            assertSame(TEST_STRING, result);
1391        }
1392    }
1393
1394    /**
1395     * completed submit of runnable returns successfully
1396     */
1397    public void testSubmitRunnable() throws Exception {
1398        final ExecutorService e =
1399            new CustomTPE(2, 2,
1400                          LONG_DELAY_MS, MILLISECONDS,
1401                          new ArrayBlockingQueue<Runnable>(10));
1402        try (PoolCleaner cleaner = cleaner(e)) {
1403            Future<?> future = e.submit(new NoOpRunnable());
1404            future.get();
1405            assertTrue(future.isDone());
1406        }
1407    }
1408
1409    /**
1410     * completed submit of (runnable, result) returns result
1411     */
1412    public void testSubmitRunnable2() throws Exception {
1413        final ExecutorService e =
1414            new CustomTPE(2, 2,
1415                          LONG_DELAY_MS, MILLISECONDS,
1416                          new ArrayBlockingQueue<Runnable>(10));
1417        try (PoolCleaner cleaner = cleaner(e)) {
1418            Future<String> future = e.submit(new NoOpRunnable(), TEST_STRING);
1419            String result = future.get();
1420            assertSame(TEST_STRING, result);
1421        }
1422    }
1423
1424    /**
1425     * invokeAny(null) throws NullPointerException
1426     */
1427    public void testInvokeAny1() throws Exception {
1428        final ExecutorService e =
1429            new CustomTPE(2, 2,
1430                          LONG_DELAY_MS, MILLISECONDS,
1431                          new ArrayBlockingQueue<Runnable>(10));
1432        try (PoolCleaner cleaner = cleaner(e)) {
1433            try {
1434                e.invokeAny(null);
1435                shouldThrow();
1436            } catch (NullPointerException success) {}
1437        }
1438    }
1439
1440    /**
1441     * invokeAny(empty collection) throws IllegalArgumentException
1442     */
1443    public void testInvokeAny2() throws Exception {
1444        final ExecutorService e =
1445            new CustomTPE(2, 2,
1446                          LONG_DELAY_MS, MILLISECONDS,
1447                          new ArrayBlockingQueue<Runnable>(10));
1448        try (PoolCleaner cleaner = cleaner(e)) {
1449            try {
1450                e.invokeAny(new ArrayList<Callable<String>>());
1451                shouldThrow();
1452            } catch (IllegalArgumentException success) {}
1453        }
1454    }
1455
1456    /**
1457     * invokeAny(c) throws NPE if c has null elements
1458     */
1459    public void testInvokeAny3() throws Exception {
1460        CountDownLatch latch = new CountDownLatch(1);
1461        final ExecutorService e =
1462            new CustomTPE(2, 2,
1463                          LONG_DELAY_MS, MILLISECONDS,
1464                          new ArrayBlockingQueue<Runnable>(10));
1465        try (PoolCleaner cleaner = cleaner(e)) {
1466            List<Callable<String>> l = new ArrayList<>();
1467            l.add(latchAwaitingStringTask(latch));
1468            l.add(null);
1469            try {
1470                e.invokeAny(l);
1471                shouldThrow();
1472            } catch (NullPointerException success) {}
1473            latch.countDown();
1474        }
1475    }
1476
1477    /**
1478     * invokeAny(c) throws ExecutionException if no task completes
1479     */
1480    public void testInvokeAny4() throws Exception {
1481        final ExecutorService e =
1482            new CustomTPE(2, 2,
1483                          LONG_DELAY_MS, MILLISECONDS,
1484                          new ArrayBlockingQueue<Runnable>(10));
1485        try (PoolCleaner cleaner = cleaner(e)) {
1486            List<Callable<String>> l = new ArrayList<>();
1487            l.add(new NPETask());
1488            try {
1489                e.invokeAny(l);
1490                shouldThrow();
1491            } catch (ExecutionException success) {
1492                assertTrue(success.getCause() instanceof NullPointerException);
1493            }
1494        }
1495    }
1496
1497    /**
1498     * invokeAny(c) returns result of some task
1499     */
1500    public void testInvokeAny5() throws Exception {
1501        final ExecutorService e =
1502            new CustomTPE(2, 2,
1503                          LONG_DELAY_MS, MILLISECONDS,
1504                          new ArrayBlockingQueue<Runnable>(10));
1505        try (PoolCleaner cleaner = cleaner(e)) {
1506            List<Callable<String>> l = new ArrayList<>();
1507            l.add(new StringTask());
1508            l.add(new StringTask());
1509            String result = e.invokeAny(l);
1510            assertSame(TEST_STRING, result);
1511        }
1512    }
1513
1514    /**
1515     * invokeAll(null) throws NPE
1516     */
1517    public void testInvokeAll1() throws Exception {
1518        final ExecutorService e =
1519            new CustomTPE(2, 2,
1520                          LONG_DELAY_MS, MILLISECONDS,
1521                          new ArrayBlockingQueue<Runnable>(10));
1522        try (PoolCleaner cleaner = cleaner(e)) {
1523            try {
1524                e.invokeAll(null);
1525                shouldThrow();
1526            } catch (NullPointerException success) {}
1527        }
1528    }
1529
1530    /**
1531     * invokeAll(empty collection) returns empty list
1532     */
1533    public void testInvokeAll2() throws Exception {
1534        final ExecutorService e =
1535            new CustomTPE(2, 2,
1536                          LONG_DELAY_MS, MILLISECONDS,
1537                          new ArrayBlockingQueue<Runnable>(10));
1538        final Collection<Callable<String>> emptyCollection
1539            = Collections.emptyList();
1540        try (PoolCleaner cleaner = cleaner(e)) {
1541            List<Future<String>> r = e.invokeAll(emptyCollection);
1542            assertTrue(r.isEmpty());
1543        }
1544    }
1545
1546    /**
1547     * invokeAll(c) throws NPE if c has null elements
1548     */
1549    public void testInvokeAll3() throws Exception {
1550        final ExecutorService e =
1551            new CustomTPE(2, 2,
1552                          LONG_DELAY_MS, MILLISECONDS,
1553                          new ArrayBlockingQueue<Runnable>(10));
1554        try (PoolCleaner cleaner = cleaner(e)) {
1555            List<Callable<String>> l = new ArrayList<>();
1556            l.add(new StringTask());
1557            l.add(null);
1558            try {
1559                e.invokeAll(l);
1560                shouldThrow();
1561            } catch (NullPointerException success) {}
1562        }
1563    }
1564
1565    /**
1566     * get of element of invokeAll(c) throws exception on failed task
1567     */
1568    public void testInvokeAll4() throws Exception {
1569        final ExecutorService e =
1570            new CustomTPE(2, 2,
1571                          LONG_DELAY_MS, MILLISECONDS,
1572                          new ArrayBlockingQueue<Runnable>(10));
1573        try (PoolCleaner cleaner = cleaner(e)) {
1574            List<Callable<String>> l = new ArrayList<>();
1575            l.add(new NPETask());
1576            List<Future<String>> futures = e.invokeAll(l);
1577            assertEquals(1, futures.size());
1578            try {
1579                futures.get(0).get();
1580                shouldThrow();
1581            } catch (ExecutionException success) {
1582                assertTrue(success.getCause() instanceof NullPointerException);
1583            }
1584        }
1585    }
1586
1587    /**
1588     * invokeAll(c) returns results of all completed tasks
1589     */
1590    public void testInvokeAll5() throws Exception {
1591        final ExecutorService e =
1592            new CustomTPE(2, 2,
1593                          LONG_DELAY_MS, MILLISECONDS,
1594                          new ArrayBlockingQueue<Runnable>(10));
1595        try (PoolCleaner cleaner = cleaner(e)) {
1596            List<Callable<String>> l = new ArrayList<>();
1597            l.add(new StringTask());
1598            l.add(new StringTask());
1599            List<Future<String>> futures = e.invokeAll(l);
1600            assertEquals(2, futures.size());
1601            for (Future<String> future : futures)
1602                assertSame(TEST_STRING, future.get());
1603        }
1604    }
1605
1606    /**
1607     * timed invokeAny(null) throws NPE
1608     */
1609    public void testTimedInvokeAny1() throws Exception {
1610        final ExecutorService e =
1611            new CustomTPE(2, 2,
1612                          LONG_DELAY_MS, MILLISECONDS,
1613                          new ArrayBlockingQueue<Runnable>(10));
1614        try (PoolCleaner cleaner = cleaner(e)) {
1615            try {
1616                e.invokeAny(null, randomTimeout(), randomTimeUnit());
1617                shouldThrow();
1618            } catch (NullPointerException success) {}
1619        }
1620    }
1621
1622    /**
1623     * timed invokeAny(,,null) throws NPE
1624     */
1625    public void testTimedInvokeAnyNullTimeUnit() throws Exception {
1626        final ExecutorService e =
1627            new CustomTPE(2, 2,
1628                          LONG_DELAY_MS, MILLISECONDS,
1629                          new ArrayBlockingQueue<Runnable>(10));
1630        try (PoolCleaner cleaner = cleaner(e)) {
1631            List<Callable<String>> l = new ArrayList<>();
1632            l.add(new StringTask());
1633            try {
1634                e.invokeAny(l, randomTimeout(), null);
1635                shouldThrow();
1636            } catch (NullPointerException success) {}
1637        }
1638    }
1639
1640    /**
1641     * timed invokeAny(empty collection) throws IllegalArgumentException
1642     */
1643    public void testTimedInvokeAny2() throws Exception {
1644        final ExecutorService e =
1645            new CustomTPE(2, 2,
1646                          LONG_DELAY_MS, MILLISECONDS,
1647                          new ArrayBlockingQueue<Runnable>(10));
1648        final Collection<Callable<String>> emptyCollection
1649            = Collections.emptyList();
1650        try (PoolCleaner cleaner = cleaner(e)) {
1651            try {
1652                e.invokeAny(emptyCollection, randomTimeout(), randomTimeUnit());
1653                shouldThrow();
1654            } catch (IllegalArgumentException success) {}
1655        }
1656    }
1657
1658    /**
1659     * timed invokeAny(c) throws NPE if c has null elements
1660     */
1661    public void testTimedInvokeAny3() throws Exception {
1662        CountDownLatch latch = new CountDownLatch(1);
1663        final ExecutorService e =
1664            new CustomTPE(2, 2,
1665                          LONG_DELAY_MS, MILLISECONDS,
1666                          new ArrayBlockingQueue<Runnable>(10));
1667        try (PoolCleaner cleaner = cleaner(e)) {
1668            List<Callable<String>> l = new ArrayList<>();
1669            l.add(latchAwaitingStringTask(latch));
1670            l.add(null);
1671            try {
1672                e.invokeAny(l, randomTimeout(), MILLISECONDS);
1673                shouldThrow();
1674            } catch (NullPointerException success) {}
1675            latch.countDown();
1676        }
1677    }
1678
1679    /**
1680     * timed invokeAny(c) throws ExecutionException if no task completes
1681     */
1682    public void testTimedInvokeAny4() throws Exception {
1683        final ExecutorService e =
1684            new CustomTPE(2, 2,
1685                          LONG_DELAY_MS, MILLISECONDS,
1686                          new ArrayBlockingQueue<Runnable>(10));
1687        try (PoolCleaner cleaner = cleaner(e)) {
1688            long startTime = System.nanoTime();
1689            List<Callable<String>> l = new ArrayList<>();
1690            l.add(new NPETask());
1691            try {
1692                e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
1693                shouldThrow();
1694            } catch (ExecutionException success) {
1695                assertTrue(success.getCause() instanceof NullPointerException);
1696            }
1697            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
1698        }
1699    }
1700
1701    /**
1702     * timed invokeAny(c) returns result of some task
1703     */
1704    public void testTimedInvokeAny5() throws Exception {
1705        final ExecutorService e =
1706            new CustomTPE(2, 2,
1707                          LONG_DELAY_MS, MILLISECONDS,
1708                          new ArrayBlockingQueue<Runnable>(10));
1709        try (PoolCleaner cleaner = cleaner(e)) {
1710            long startTime = System.nanoTime();
1711            List<Callable<String>> l = new ArrayList<>();
1712            l.add(new StringTask());
1713            l.add(new StringTask());
1714            String result = e.invokeAny(l, LONG_DELAY_MS, MILLISECONDS);
1715            assertSame(TEST_STRING, result);
1716            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
1717        }
1718    }
1719
1720    /**
1721     * timed invokeAll(null) throws NPE
1722     */
1723    public void testTimedInvokeAll1() throws Exception {
1724        final ExecutorService e =
1725            new CustomTPE(2, 2,
1726                          LONG_DELAY_MS, MILLISECONDS,
1727                          new ArrayBlockingQueue<Runnable>(10));
1728        try (PoolCleaner cleaner = cleaner(e)) {
1729            try {
1730                e.invokeAll(null, randomTimeout(), randomTimeUnit());
1731                shouldThrow();
1732            } catch (NullPointerException success) {}
1733        }
1734    }
1735
1736    /**
1737     * timed invokeAll(,,null) throws NPE
1738     */
1739    public void testTimedInvokeAllNullTimeUnit() throws Exception {
1740        final ExecutorService e =
1741            new CustomTPE(2, 2,
1742                          LONG_DELAY_MS, MILLISECONDS,
1743                          new ArrayBlockingQueue<Runnable>(10));
1744        try (PoolCleaner cleaner = cleaner(e)) {
1745            List<Callable<String>> l = new ArrayList<>();
1746            l.add(new StringTask());
1747            try {
1748                e.invokeAll(l, randomTimeout(), null);
1749                shouldThrow();
1750            } catch (NullPointerException success) {}
1751        }
1752    }
1753
1754    /**
1755     * timed invokeAll(empty collection) returns empty list
1756     */
1757    public void testTimedInvokeAll2() throws Exception {
1758        final ExecutorService e =
1759            new CustomTPE(2, 2,
1760                          LONG_DELAY_MS, MILLISECONDS,
1761                          new ArrayBlockingQueue<Runnable>(10));
1762        final Collection<Callable<String>> emptyCollection
1763            = Collections.emptyList();
1764        try (PoolCleaner cleaner = cleaner(e)) {
1765            List<Future<String>> r =
1766                e.invokeAll(emptyCollection, randomTimeout(), randomTimeUnit());
1767            assertTrue(r.isEmpty());
1768        }
1769    }
1770
1771    /**
1772     * timed invokeAll(c) throws NPE if c has null elements
1773     */
1774    public void testTimedInvokeAll3() throws Exception {
1775        final ExecutorService e =
1776            new CustomTPE(2, 2,
1777                          LONG_DELAY_MS, MILLISECONDS,
1778                          new ArrayBlockingQueue<Runnable>(10));
1779        try (PoolCleaner cleaner = cleaner(e)) {
1780            List<Callable<String>> l = new ArrayList<>();
1781            l.add(new StringTask());
1782            l.add(null);
1783            try {
1784                e.invokeAll(l, randomTimeout(), randomTimeUnit());
1785                shouldThrow();
1786            } catch (NullPointerException success) {}
1787        }
1788    }
1789
1790    /**
1791     * get of element of invokeAll(c) throws exception on failed task
1792     */
1793    public void testTimedInvokeAll4() throws Exception {
1794        final ExecutorService e =
1795            new CustomTPE(2, 2,
1796                          LONG_DELAY_MS, MILLISECONDS,
1797                          new ArrayBlockingQueue<Runnable>(10));
1798        try (PoolCleaner cleaner = cleaner(e)) {
1799            List<Callable<String>> l = new ArrayList<>();
1800            l.add(new NPETask());
1801            List<Future<String>> futures =
1802                e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
1803            assertEquals(1, futures.size());
1804            try {
1805                futures.get(0).get();
1806                shouldThrow();
1807            } catch (ExecutionException success) {
1808                assertTrue(success.getCause() instanceof NullPointerException);
1809            }
1810        }
1811    }
1812
1813    /**
1814     * timed invokeAll(c) returns results of all completed tasks
1815     */
1816    public void testTimedInvokeAll5() throws Exception {
1817        final ExecutorService e =
1818            new CustomTPE(2, 2,
1819                          LONG_DELAY_MS, MILLISECONDS,
1820                          new ArrayBlockingQueue<Runnable>(10));
1821        try (PoolCleaner cleaner = cleaner(e)) {
1822            List<Callable<String>> l = new ArrayList<>();
1823            l.add(new StringTask());
1824            l.add(new StringTask());
1825            List<Future<String>> futures =
1826                e.invokeAll(l, LONG_DELAY_MS, MILLISECONDS);
1827            assertEquals(2, futures.size());
1828            for (Future<String> future : futures)
1829                assertSame(TEST_STRING, future.get());
1830        }
1831    }
1832
1833    /**
1834     * timed invokeAll(c) cancels tasks not completed by timeout
1835     */
1836    public void testTimedInvokeAll6() throws Exception {
1837        for (long timeout = timeoutMillis();;) {
1838            final CountDownLatch done = new CountDownLatch(1);
1839            final Callable<String> waiter = new CheckedCallable<String>() {
1840                public String realCall() {
1841                    try { done.await(LONG_DELAY_MS, MILLISECONDS); }
1842                    catch (InterruptedException ok) {}
1843                    return "1"; }};
1844            final ExecutorService p =
1845                new CustomTPE(2, 2,
1846                              LONG_DELAY_MS, MILLISECONDS,
1847                              new ArrayBlockingQueue<Runnable>(10));
1848            try (PoolCleaner cleaner = cleaner(p, done)) {
1849                List<Callable<String>> tasks = new ArrayList<>();
1850                tasks.add(new StringTask("0"));
1851                tasks.add(waiter);
1852                tasks.add(new StringTask("2"));
1853                long startTime = System.nanoTime();
1854                List<Future<String>> futures =
1855                    p.invokeAll(tasks, timeout, MILLISECONDS);
1856                assertEquals(tasks.size(), futures.size());
1857                assertTrue(millisElapsedSince(startTime) >= timeout);
1858                for (Future future : futures)
1859                    assertTrue(future.isDone());
1860                assertTrue(futures.get(1).isCancelled());
1861                try {
1862                    assertEquals("0", futures.get(0).get());
1863                    assertEquals("2", futures.get(2).get());
1864                    break;
1865                } catch (CancellationException retryWithLongerTimeout) {
1866                    timeout *= 2;
1867                    if (timeout >= LONG_DELAY_MS / 2)
1868                        fail("expected exactly one task to be cancelled");
1869                }
1870            }
1871        }
1872    }
1873
1874    /**
1875     * Execution continues if there is at least one thread even if
1876     * thread factory fails to create more
1877     */
1878    public void testFailingThreadFactory() throws InterruptedException {
1879        final ExecutorService e =
1880            new CustomTPE(100, 100,
1881                          LONG_DELAY_MS, MILLISECONDS,
1882                          new LinkedBlockingQueue<Runnable>(),
1883                          new FailingThreadFactory());
1884        try (PoolCleaner cleaner = cleaner(e)) {
1885            final int TASKS = 100;
1886            final CountDownLatch done = new CountDownLatch(TASKS);
1887            for (int k = 0; k < TASKS; ++k)
1888                e.execute(new CheckedRunnable() {
1889                    public void realRun() {
1890                        done.countDown();
1891                    }});
1892            await(done);
1893        }
1894    }
1895
1896    /**
1897     * allowsCoreThreadTimeOut is by default false.
1898     */
1899    public void testAllowsCoreThreadTimeOut() {
1900        final ThreadPoolExecutor p =
1901            new CustomTPE(2, 2,
1902                          1000, MILLISECONDS,
1903                          new ArrayBlockingQueue<Runnable>(10));
1904        try (PoolCleaner cleaner = cleaner(p)) {
1905            assertFalse(p.allowsCoreThreadTimeOut());
1906        }
1907    }
1908
1909    /**
1910     * allowCoreThreadTimeOut(true) causes idle threads to time out
1911     */
1912    public void testAllowCoreThreadTimeOut_true() throws Exception {
1913        long keepAliveTime = timeoutMillis();
1914        final ThreadPoolExecutor p =
1915            new CustomTPE(2, 10,
1916                          keepAliveTime, MILLISECONDS,
1917                          new ArrayBlockingQueue<Runnable>(10));
1918        try (PoolCleaner cleaner = cleaner(p)) {
1919            final CountDownLatch threadStarted = new CountDownLatch(1);
1920            p.allowCoreThreadTimeOut(true);
1921            p.execute(new CheckedRunnable() {
1922                public void realRun() {
1923                    threadStarted.countDown();
1924                    assertEquals(1, p.getPoolSize());
1925                }});
1926            await(threadStarted);
1927            delay(keepAliveTime);
1928            long startTime = System.nanoTime();
1929            while (p.getPoolSize() > 0
1930                   && millisElapsedSince(startTime) < LONG_DELAY_MS)
1931                Thread.yield();
1932            assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
1933            assertEquals(0, p.getPoolSize());
1934        }
1935    }
1936
1937    /**
1938     * allowCoreThreadTimeOut(false) causes idle threads not to time out
1939     */
1940    public void testAllowCoreThreadTimeOut_false() throws Exception {
1941        long keepAliveTime = timeoutMillis();
1942        final ThreadPoolExecutor p =
1943            new CustomTPE(2, 10,
1944                          keepAliveTime, MILLISECONDS,
1945                          new ArrayBlockingQueue<Runnable>(10));
1946        try (PoolCleaner cleaner = cleaner(p)) {
1947            final CountDownLatch threadStarted = new CountDownLatch(1);
1948            p.allowCoreThreadTimeOut(false);
1949            p.execute(new CheckedRunnable() {
1950                public void realRun() throws InterruptedException {
1951                    threadStarted.countDown();
1952                    assertTrue(p.getPoolSize() >= 1);
1953                }});
1954            delay(2 * keepAliveTime);
1955            assertTrue(p.getPoolSize() >= 1);
1956        }
1957    }
1958
1959    /**
1960     * get(cancelled task) throws CancellationException
1961     * (in part, a test of CustomTPE itself)
1962     */
1963    public void testGet_cancelled() throws Exception {
1964        final CountDownLatch done = new CountDownLatch(1);
1965        final ExecutorService e =
1966            new CustomTPE(1, 1,
1967                          LONG_DELAY_MS, MILLISECONDS,
1968                          new LinkedBlockingQueue<Runnable>());
1969        try (PoolCleaner cleaner = cleaner(e, done)) {
1970            final CountDownLatch blockerStarted = new CountDownLatch(1);
1971            final List<Future<?>> futures = new ArrayList<>();
1972            for (int i = 0; i < 2; i++) {
1973                Runnable r = new CheckedRunnable() { public void realRun()
1974                                                         throws Throwable {
1975                    blockerStarted.countDown();
1976                    assertTrue(done.await(2 * LONG_DELAY_MS, MILLISECONDS));
1977                }};
1978                futures.add(e.submit(r));
1979            }
1980            await(blockerStarted);
1981            for (Future<?> future : futures) future.cancel(false);
1982            for (Future<?> future : futures) {
1983                try {
1984                    future.get();
1985                    shouldThrow();
1986                } catch (CancellationException success) {}
1987                try {
1988                    future.get(LONG_DELAY_MS, MILLISECONDS);
1989                    shouldThrow();
1990                } catch (CancellationException success) {}
1991                assertTrue(future.isCancelled());
1992                assertTrue(future.isDone());
1993            }
1994        }
1995    }
1996
1997}
1998