fix: prevent carrier starvation in ForkJoinTask context propagation - #628
Closed
zhengziyi0117 wants to merge 1 commit into
Closed
fix: prevent carrier starvation in ForkJoinTask context propagation#628zhengziyi0117 wants to merge 1 commit into
zhengziyi0117 wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ForkJoinTask advice can exhaust the default virtual-thread scheduler on JDK 21 by polling
CAPTURED_CACHEfrom carrier threads. If a virtual thread is the first waiter for the cache'sReferenceQueuelock and every carrier then blocks behind it, releasing the lock leaves the virtual thread runnable with no carrier available to resume it.Skip context capture and replay on
jdk.internal.misc.CarrierThreadbefore either ForkJoinTask advice accesses the shared cache. Mounted virtual threads and ordinary ForkJoinPool workers retain the existing behavior. The helper remains Java 8 compatible and targets the JDK's default scheduler.Regression coverage
ForkJoinCarrierThreadTeststarts isolated JVMs with two real carriers and a Byte Buddy test agent weaving ForkJoinTask constructors and execution methods. Explicit reference enqueueing and controlled lock acquisition put the virtual thread first in the AQS queue without relying on GC timing.lockHeld=false, the VT isRUNNABLE, all three waiters remain queued, and neither carrier probe completes.Validation
On OpenJDK 21.0.2:
mvn -pl arex-instrumentation/internal/arex-executors -am test364 tests passed (137 bootstrap, 203 instrumentation API, 24 executors), with no failures, errors, or skips. All seven changed Java files also compiled with JDK 8 (Zulu 8.0.422).
To run only the before/after reproducer:
mvn -pl arex-instrumentation/internal/arex-executors -am \ -Dtest=ForkJoinCarrierThreadTest \ -Dsurefire.failIfNoSpecifiedTests=false testThe test agent validates the actual advice in the JDK scheduling path; it does not start the full AREX agent or require backend services.