From 0231ed9e9cb2041a3bf5c7ef5e32c22ddecf93db Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 3 Jun 2026 18:58:17 +0200 Subject: [PATCH] 8385830 - addressing a race-condition in ForkJoinTask where interrupting the thread waiting for the result sometimes leads to a lost interruption --- .../java/util/concurrent/ForkJoinTask.java | 16 ++++++---------- .../util/concurrent/tck/ForkJoinPoolTest.java | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 137cac45ed060..f39d92aeeb400 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -418,19 +418,15 @@ else if (((a = aux) == null || a.ex == null) && for (;;) { if ((s = status) < 0) break; - else if (interrupts < 0) { - s = ABNORMAL; // interrupted and not done - break; - } else if (Thread.interrupted()) { - if (!ForkJoinPool.poolIsStopping(pool)) - interrupts = interruptible ? -1 : 1; - else { - interrupts = 1; // re-assert if cleared + if (ForkJoinPool.poolIsStopping(pool)) { try { cancel(true); - } catch (Throwable ignore) { - } + } catch (Throwable ignore) { } + } + if ((interrupts = interruptible ? -1 : 1) < 0) { + s = ABNORMAL; + break; } } else if (deadline != 0L) { diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java index de1caaab2d941..85d7921f2ed84 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java @@ -663,6 +663,23 @@ public void realRun() throws Exception { } } + public void testCallerInterruptedDuringSubmit() throws InterruptedException, ExecutionException { + final Thread submitter = Thread.currentThread(); + final ExecutorService p = new ForkJoinPool(1); + try (PoolCleaner cleaner = cleaner(p)) { + for (int i = 0; i < 512; ++i) { // Enough repetitions such that any race condition is bound to materialize + try { + p.submit(submitter::interrupt).get(); + // If we don't get an InterruptedException, then the current thread should be interrupted + assertTrue(Thread.interrupted()); + } catch (InterruptedException e) { + // If we do get an InterruptedException, then the current thread should not be interrupted + assertTrue(!Thread.interrupted()); + } + } + } + } + /** * get of submit(callable) throws ExecutionException if callable * throws exception