From f077eb9eb0c667c767d85fc2e67bd550e1cc077d Mon Sep 17 00:00:00 2001
From: Doug Lea
Date: Sat, 3 Jan 2026 10:46:15 -0500
Subject: [PATCH] Strengthen some orderings
---
.../java/util/concurrent/ForkJoinPool.java | 51 ++++++++++++-------
1 file changed, 32 insertions(+), 19 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 5bd677cac64..94fdd3e0216 100644
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -1249,16 +1249,16 @@ public class ForkJoinPool extends AbstractExecutorService
*/
final void push(ForkJoinTask> task, ForkJoinPool pool, int unlock) {
ForkJoinTask>[] a = array;
- int b = base, s = top, m;
+ int b = base, s = top, room, m;
if (a != null &&
- (a.length > s + 1 - b || (a = growArray()) != null) &&
+ ((room = a.length - (s + 1 - b)) > 0 || (a = growArray()) != null) &&
(m = a.length - 1) >= 0) { // else rejected or disabled
top = s + 1;
U.putReferenceVolatile(a, slotOffset(m & s), task);
if (unlock != 1) // release external lock
- U.putInt(this, PHASE, unlock);
- if (U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null &&
- pool != null)
+ phase = unlock;
+ if ((U.getReferenceAcquire(a, slotOffset(m & (s - 1))) == null ||
+ room <= 0) && pool != null)
pool.signalWork(this, s); // may have appeared empty
}
}
@@ -1307,13 +1307,16 @@ public class ForkJoinPool extends AbstractExecutorService
if (a != null && s - b >= 0 && (cap = a.length) > 0) {
if (fifo == 0) {
if ((t = (ForkJoinTask>)U.getAndSetReference(
- a, slotOffset((cap - 1) & s), null)) != null)
+ a, slotOffset((cap - 1) & s), null)) != null) {
top = s;
+ U.storeFence();
+ }
} else {
do {
if ((t = (ForkJoinTask>)U.getAndSetReference(
a, slotOffset((cap - 1) & b), null)) != null) {
base = b + 1;
+ U.storeFence();
break;
}
if (b == s)
@@ -1330,10 +1333,7 @@ public class ForkJoinPool extends AbstractExecutorService
* Takes next task, if one exists, using configured mode.
*/
final ForkJoinTask> nextLocalTask() {
- U.loadFence(); // ensure ordering for external callers
- ForkJoinTask> t= nextLocalTask(config & FIFO);
- U.storeFence();
- return t;
+ return nextLocalTask(config & FIFO);
}
/**
@@ -1350,10 +1350,11 @@ public class ForkJoinPool extends AbstractExecutorService
(internal || (lock = tryLockPhase()) != 1)) {
if (top == p && U.compareAndSetReference(a, k, task, null)) {
taken = true;
- U.putIntOpaque(this, TOP, s);
+ top = s;
+ U.storeFence();
}
if (!internal)
- U.putIntRelease(this, PHASE, lock + NEXTIDLE);
+ phase = lock + NEXTIDLE;
}
return taken;
}
@@ -1413,6 +1414,7 @@ public class ForkJoinPool extends AbstractExecutorService
/**
* Runs the given task, as well as remaining local tasks
*/
+ // @jdk.internal.vm.annotation.DontInline
final void topLevelExec(ForkJoinTask> task, int fifo) {
while (task != null) {
task.doExec();
@@ -1452,9 +1454,10 @@ public class ForkJoinPool extends AbstractExecutorService
a, slotOffset(s & m), null));
top = s;
}
+ U.storeFence();
}
if (!internal)
- U.putIntRelease(this, PHASE, lock + NEXTIDLE);
+ phase = lock + NEXTIDLE;
if (taken)
task.doExec();
break;
@@ -1498,10 +1501,12 @@ public class ForkJoinPool extends AbstractExecutorService
break;
if (taken =
(top == p &&
- U.compareAndSetReference(a, k, t, null)))
+ U.compareAndSetReference(a, k, t, null))) {
top = s;
+ U.storeFence();
+ }
if (!internal)
- U.putIntRelease(this, PHASE, lock + NEXTIDLE);
+ phase = lock + NEXTIDLE;
if (!taken)
break;
t.doExec();
@@ -1537,6 +1542,7 @@ public class ForkJoinPool extends AbstractExecutorService
if (base == b && t != null &&
U.compareAndSetReference(a, k, t, null)) {
base = b + 1;
+ U.storeFence();
t.doExec();
}
}
@@ -2015,16 +2021,23 @@ public class ForkJoinPool extends AbstractExecutorService
}
long sp = (phase + NEXTIDLE) & LMASK, pc = ctl;
U.putInt(w, WorkQueue.PHASE, phase | IDLE);
- for (long c;;) { // try to enqueue
+ for (;;) { // try to enqueue
+ long c, e;
w.stackPred = (int)pc;
if (pc == (pc = U.compareAndExchangeLong(
this, CTL, pc, c = ((pc - RC_UNIT) & UMASK) | sp))) {
idle = IDLE;
- if ((c & RC_MASK) == 0L)
- quiescent(); // check quiescent termination
+ if (((e = runState) & STOP) == 0L &&
+ ((e & SHUTDOWN) == 0L || (c & RC_MASK) > 0L ||
+ quiescent() <= 0)) { // spin for approx 1 scan cost
+ int tc = (short)(c >>> TC_SHIFT);
+ int spins = Math.max((tc << 1) + tc, SPIN_WAITS);
+ while ((idle = w.phase & IDLE) != 0 && --spins != 0)
+ Thread.onSpinWait();
+ }
break;
}
- else if ((c & RC_MASK) <= (pc & RC_MASK)) {
+ else if ((c & RC_MASK) < (pc & RC_MASK)) {
w.phase = phase; // back out if lost to signal
break;
}