diff --git a/core/deployment/src/main/java/io/quarkus/deployment/ForkJoinPoolProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/ForkJoinPoolProcessor.java new file mode 100644 index 0000000000000..e98be4904efa0 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/ForkJoinPoolProcessor.java @@ -0,0 +1,13 @@ +package io.quarkus.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.SystemPropertyBuildItem; + +public final class ForkJoinPoolProcessor { + + @BuildStep + SystemPropertyBuildItem setProperty() { + return new SystemPropertyBuildItem("java.util.concurrent.ForkJoinPool.common.threadFactory", + "io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory"); + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java index efda17aec2d07..93a1db5e1cbf9 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/QuarkusDevModeLauncher.java @@ -407,6 +407,8 @@ protected void prepare() throws Exception { devModeContext.getAdditionalModules().addAll(dependencies); args.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager"); + args.add( + "-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory"); File tempFile = new File(buildDir, applicationName + "-dev.jar"); tempFile.delete(); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java index 02dd62fd04ab6..2dda2885e0142 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/jbang/JBangAugmentorImpl.java @@ -124,6 +124,8 @@ public void accept(BuildChainBuilder builder) { resultMap.put("files", result); List javaargs = new ArrayList(); javaargs.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager"); + javaargs.add( + "-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory"); resultMap.put("java-args", javaargs); resultMap.put("main-class", buildResult.consume(MainClassBuildItem.class).getClassName()); if (nativeRequested) { diff --git a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java index e6ecf8b5f4d11..6f8276a9d136d 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java @@ -7,6 +7,7 @@ import org.jboss.logging.Logger; import org.jboss.logmanager.LogManager; +import io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory; import io.quarkus.launcher.QuarkusLauncher; /** @@ -58,6 +59,8 @@ public static void run(Class quarkusApplication, B String... args) { try { System.setProperty("java.util.logging.manager", LogManager.class.getName()); + System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", + QuarkusForkJoinWorkerThreadFactory.class.getName()); //production and common dev mode path //we already have an application, run it directly Class appClass = (Class) Class.forName(Application.APP_CLASS_NAME, diff --git a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThread.java b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThread.java new file mode 100644 index 0000000000000..ec8a205bb1f0c --- /dev/null +++ b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThread.java @@ -0,0 +1,36 @@ +package io.quarkus.bootstrap.forkjoin; + +import io.quarkus.bootstrap.runner.RunnerClassLoader; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; + +public class QuarkusForkJoinWorkerThread extends ForkJoinWorkerThread { + + private static volatile ClassLoader qClassloader; + + protected QuarkusForkJoinWorkerThread(ForkJoinPool pool) { + super(pool); + } + + public static synchronized void setQuarkusAppClassloader(RunnerClassLoader runnerClassLoader) { + if (qClassloader != null) { + throw new IllegalStateException("Attempting to set the Quarkus root classloader while it was already set"); + } + if (runnerClassLoader == null) { + throw new IllegalStateException("Attempting to set the Quarkus root classloader to null"); + } + qClassloader = runnerClassLoader; + } + + protected void onStart() { + super.onStart(); + if (qClassloader == null) { + throw new IllegalStateException( + "Fork Join pool initialization has been triggered before the primary classloader has been initialized. " + + "Use this stacktrace to figure out what triggered it, and avoid using the Fork Join pool this early during the boot process."); + } else { + super.setContextClassLoader(qClassloader); + } + } + +} diff --git a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThreadFactory.java b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThreadFactory.java new file mode 100644 index 0000000000000..aa30a8e22aad4 --- /dev/null +++ b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/forkjoin/QuarkusForkJoinWorkerThreadFactory.java @@ -0,0 +1,16 @@ +package io.quarkus.bootstrap.forkjoin; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; + +public final class QuarkusForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory { + + public QuarkusForkJoinWorkerThreadFactory() { + //Needs a public constructor for the JDK to pick it up + } + + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + return new QuarkusForkJoinWorkerThread(pool); + } +} diff --git a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java index 2ae1c385cfe5a..6b543df188648 100644 --- a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java +++ b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/QuarkusEntryPoint.java @@ -1,5 +1,6 @@ package io.quarkus.bootstrap.runner; +import io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThread; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; @@ -21,6 +22,8 @@ public class QuarkusEntryPoint { public static void main(String... args) throws Throwable { System.setProperty("java.util.logging.manager", org.jboss.logmanager.LogManager.class.getName()); + System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", + "io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory"); Timing.staticInitStarted(false); doRun(args); } @@ -44,6 +47,7 @@ private static void doRun(Object args) throws IOException, ClassNotFoundExceptio } try { Thread.currentThread().setContextClassLoader(app.getRunnerClassLoader()); + QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(app.getRunnerClassLoader()); Class mainClass = app.getRunnerClassLoader().loadClass(app.getMainClass()); mainClass.getMethod("main", String[].class).invoke(null, args); } finally {