8221892: ThreadPoolExecutor: Thread.isAlive() is not equivalent to not being startable
authordl
Thu, 02 May 2019 06:33:28 -0700
changeset 54684 c277ec29ee12
parent 54683 3ffdc15cd044
child 54685 e1bec7613945
8221892: ThreadPoolExecutor: Thread.isAlive() is not equivalent to not being startable Reviewed-by: martin, dholmes
src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java
test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java	Thu May 02 06:33:28 2019 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java	Thu May 02 06:33:28 2019 -0700
@@ -922,13 +922,13 @@
 
                     if (isRunning(c) ||
                         (runStateLessThan(c, STOP) && firstTask == null)) {
-                        if (t.isAlive()) // precheck that t is startable
+                        if (t.getState() != Thread.State.NEW)
                             throw new IllegalThreadStateException();
                         workers.add(w);
+                        workerAdded = true;
                         int s = workers.size();
                         if (s > largestPoolSize)
                             largestPoolSize = s;
-                        workerAdded = true;
                     }
                 } finally {
                     mainLock.unlock();
--- a/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Thu May 02 06:33:28 2019 -0700
+++ b/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Thu May 02 06:33:28 2019 -0700
@@ -2011,4 +2011,49 @@
         assertTrue(p.getQueue().isEmpty());
     }
 
+    public void testThreadFactoryReturnsTerminatedThread_shouldThrow() {
+        if (!testImplementationDetails)
+            return;
+
+        ThreadFactory returnsTerminatedThread = runnableIgnored -> {
+            Thread thread = new Thread(() -> {});
+            thread.start();
+            try { thread.join(); }
+            catch (InterruptedException ex) { throw new Error(ex); }
+            return thread;
+        };
+        ThreadPoolExecutor p =
+            new ThreadPoolExecutor(1, 1, 1, SECONDS,
+                                   new ArrayBlockingQueue<Runnable>(1),
+                                   returnsTerminatedThread);
+        try (PoolCleaner cleaner = cleaner(p)) {
+            assertThrows(IllegalThreadStateException.class,
+                         () -> p.execute(() -> {}));
+        }
+    }
+
+    public void testThreadFactoryReturnsStartedThread_shouldThrow() {
+        if (!testImplementationDetails)
+            return;
+
+        CountDownLatch latch = new CountDownLatch(1);
+        Runnable awaitLatch = () -> {
+            try { latch.await(); }
+            catch (InterruptedException ex) { throw new Error(ex); }};
+        ThreadFactory returnsStartedThread = runnable -> {
+            Thread thread = new Thread(awaitLatch);
+            thread.start();
+            return thread;
+        };
+        ThreadPoolExecutor p =
+            new ThreadPoolExecutor(1, 1, 1, SECONDS,
+                                   new ArrayBlockingQueue<Runnable>(1),
+                                   returnsStartedThread);
+        try (PoolCleaner cleaner = cleaner(p)) {
+            assertThrows(IllegalThreadStateException.class,
+                         () -> p.execute(() -> {}));
+            latch.countDown();
+        }
+    }
+
 }