From 2c034f57d6b4229aaf195fdd6efd016cf694855f Mon Sep 17 00:00:00 2001
From: Doug Lea
Date: Mon, 26 May 2025 22:37:42 +0000
Subject: [PATCH] 8357146: ForkJoinPool:schedule(*) does not throw
RejectedExecutionException when pool is shutdown
Reviewed-by: alanb
---
.../java/util/concurrent/ForkJoinPool.java | 22 +++++++++++++------
.../concurrent/tck/ForkJoinPool20Test.java | 18 +++++++++++++++
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
index eac0f5bdc18..a7821921bc9 100644
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -3452,9 +3452,9 @@ public class ForkJoinPool extends AbstractExecutorService
String name = poolName + "-delayScheduler";
if (workerNamePrefix == null)
asyncCommonPool(); // override common parallelism zero
- lockRunState();
+ long isShutdown = lockRunState() & SHUTDOWN;
try {
- if ((ds = delayScheduler) == null) {
+ if (isShutdown == 0L && (ds = delayScheduler) == null) {
ds = delayScheduler = new DelayScheduler(this, name);
start = true;
}
@@ -3462,12 +3462,20 @@ public class ForkJoinPool extends AbstractExecutorService
unlockRunState();
}
if (start) { // start outside of lock
- // exceptions on start passed to (external) callers
SharedThreadContainer ctr;
- if ((ctr = container) != null)
- ctr.start(ds);
- else
- ds.start();
+ try {
+ if ((ctr = container) != null)
+ ctr.start(ds);
+ else
+ ds.start();
+ } catch (RuntimeException | Error ex) { // back out
+ lockRunState();
+ ds = delayScheduler = null;
+ unlockRunState();
+ tryTerminate(false, false);
+ if (ex instanceof Error)
+ throw ex;
+ }
}
}
return ds;
diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java b/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java
index 9b60bbae484..9e26ec11d72 100644
--- a/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool20Test.java
@@ -644,4 +644,22 @@ public class ForkJoinPool20Test extends JSR166TestCase {
}
}
+ /**
+ * schedule throws RejectedExecutionException if shutdown before
+ * first delayed task is submitted
+ */
+ public void testInitialScheduleAfterShutdown() throws InterruptedException {
+ Runnable r = new NoOpRunnable();
+ boolean rje = false;
+ try (final ForkJoinPool p = new ForkJoinPool(1)) {
+ p.shutdown();
+ assertTrue(p.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
+ try {
+ p.schedule(r, 1, MILLISECONDS);
+ } catch (RejectedExecutionException ok) {
+ rje = true;
+ }
+ }
+ assertTrue(rje);
+ }
}