Skip to content

Commit 14babee

Browse files
committed
Use MethodHandle.invokeExact for VT factory, conditionally wrap worker executor
Replace reflection with MethodHandle.invokeExact (adapted via asType for JDK 11 source compatibility). Only wrap worker executors with WrappedWorkerExecutorService when a custom ExecutorServiceFactory is provided, avoiding per-task lambda+VtInfo allocation overhead in the default VertxThread case.
1 parent 34fbf99 commit 14babee

2 files changed

Lines changed: 38 additions & 16 deletions

File tree

vertx-core/src/main/java/io/vertx/core/impl/VertxImpl.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,12 @@ private static ThreadFactory virtualThreadFactory() {
189189
long maxWorkerExecuteTime = options.getMaxWorkerExecuteTime();
190190

191191
ThreadFactory workerThreadFactory = createThreadFactory(threadFactory, checker, useDaemonThread, maxWorkerExecuteTime, maxWorkerExecuteTimeUnit, "vert.x-worker-thread-", true);
192-
ExecutorService workerExec = new WrappedWorkerExecutorService(
193-
executorServiceFactory.createExecutor(workerThreadFactory, workerPoolSize, workerPoolSize), true, this);
192+
ExecutorService workerExec = wrapWorkerExecutor(
193+
executorServiceFactory.createExecutor(workerThreadFactory, workerPoolSize, workerPoolSize), executorServiceFactory);
194194
PoolMetrics workerPoolMetrics = metrics != null ? metrics.createPoolMetrics("worker", "vert.x-worker-thread", options.getWorkerPoolSize()) : null;
195195
ThreadFactory internalWorkerThreadFactory = createThreadFactory(threadFactory, checker, useDaemonThread, maxWorkerExecuteTime, maxWorkerExecuteTimeUnit, "vert.x-internal-blocking-", true);
196-
ExecutorService internalWorkerExec = new WrappedWorkerExecutorService(
197-
executorServiceFactory.createExecutor(internalWorkerThreadFactory, internalBlockingPoolSize, internalBlockingPoolSize), true, this);
196+
ExecutorService internalWorkerExec = wrapWorkerExecutor(
197+
executorServiceFactory.createExecutor(internalWorkerThreadFactory, internalBlockingPoolSize, internalBlockingPoolSize), executorServiceFactory);
198198
PoolMetrics internalBlockingPoolMetrics = metrics != null ? metrics.createPoolMetrics("worker", "vert.x-internal-blocking", internalBlockingPoolSize) : null;
199199

200200
ThreadFactory virtualThreadFactory = virtualThreadFactory();
@@ -1118,8 +1118,8 @@ private synchronized WorkerPool createSharedWorkerPool(CloseFuture closeFuture,
11181118
}
11191119
WorkerPool shared = createSharedResource("__vertx.shared.workerPools", name, closeFuture, cf -> {
11201120
ThreadFactory workerThreadFactory = createThreadFactory(threadFactory, checker, useDaemonThread, maxExecuteTime, maxExecuteTimeUnit, name + "-", true);
1121-
ExecutorService workerExec = new WrappedWorkerExecutorService(
1122-
executorServiceFactory.createExecutor(workerThreadFactory, poolSize, poolSize), true, VertxImpl.this);
1121+
ExecutorService workerExec = wrapWorkerExecutor(
1122+
executorServiceFactory.createExecutor(workerThreadFactory, poolSize, poolSize), executorServiceFactory);
11231123
PoolMetrics workerMetrics = metrics != null ? metrics.createPoolMetrics("worker", name, poolSize) : null;
11241124
WorkerPool pool = new WorkerPool(workerExec, workerMetrics);
11251125
cf.add(completion -> {
@@ -1155,6 +1155,20 @@ private ThreadFactory createThreadFactory(VertxThreadFactory threadFactory, Bloc
11551155
};
11561156
}
11571157

1158+
/**
1159+
* Wrap the executor with {@link WrappedWorkerExecutorService} only when a custom
1160+
* {@link ExecutorServiceFactory} is used, since its threads may not be {@link VertxThread}
1161+
* instances (e.g. virtual threads) and need CHM-based identity registration for
1162+
* {@link VertxThread#isVertxThread()}, {@link VertxThread#isCurrentWorker()} etc. to work.
1163+
* Skipped for the default factory whose threads are already {@link VertxThread}.
1164+
*/
1165+
private ExecutorService wrapWorkerExecutor(ExecutorService exec, ExecutorServiceFactory factory) {
1166+
if (factory != ExecutorServiceFactory.INSTANCE) {
1167+
return new WrappedWorkerExecutorService(exec, true, this);
1168+
}
1169+
return exec;
1170+
}
1171+
11581172
@Override
11591173
public Vertx exceptionHandler(Handler<Throwable> handler) {
11601174
exceptionHandler = handler;

vertx-core/src/main/java/io/vertx/core/impl/VertxThread.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import io.vertx.core.internal.threadchecker.ThreadInfo;
1616
import io.vertx.core.internal.ContextInternal;
1717

18-
import java.lang.reflect.Method;
18+
import java.lang.invoke.MethodHandle;
19+
import java.lang.invoke.MethodHandles;
20+
import java.lang.invoke.MethodType;
1921
import java.util.concurrent.ConcurrentHashMap;
2022
import java.util.concurrent.ThreadFactory;
2123
import java.util.concurrent.TimeUnit;
@@ -39,15 +41,21 @@ public class VertxThread extends FastThreadLocalThread {
3941
*/
4042
public static ThreadFactory virtualThreadFactory(String prefix) {
4143
try {
42-
Class<?> builderClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.Thread$Builder");
43-
Class<?> ofVirtualClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.Thread$Builder$OfVirtual");
44-
Method ofVirtualMethod = Thread.class.getDeclaredMethod("ofVirtual");
45-
Object builder = ofVirtualMethod.invoke(null);
46-
Method nameMethod = ofVirtualClass.getDeclaredMethod("name", String.class, long.class);
47-
Method factoryMethod = builderClass.getDeclaredMethod("factory");
48-
builder = nameMethod.invoke(builder, prefix, 0L);
49-
return (ThreadFactory) factoryMethod.invoke(builder);
50-
} catch (Exception e) {
44+
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
45+
Class<?> builderClass = Class.forName("java.lang.Thread$Builder");
46+
Class<?> ofVirtualClass = Class.forName("java.lang.Thread$Builder$OfVirtual");
47+
MethodHandle ofVirtual = lookup.findStatic(Thread.class, "ofVirtual",
48+
MethodType.methodType(ofVirtualClass)).asType(MethodType.methodType(Object.class));
49+
MethodHandle name = lookup.findVirtual(ofVirtualClass, "name",
50+
MethodType.methodType(ofVirtualClass, String.class, long.class))
51+
.asType(MethodType.methodType(Object.class, Object.class, String.class, long.class));
52+
MethodHandle factory = lookup.findVirtual(builderClass, "factory",
53+
MethodType.methodType(ThreadFactory.class))
54+
.asType(MethodType.methodType(ThreadFactory.class, Object.class));
55+
Object builder = (Object) ofVirtual.invokeExact();
56+
builder = (Object) name.invokeExact(builder, prefix, 0L);
57+
return (ThreadFactory) factory.invokeExact(builder);
58+
} catch (Throwable e) {
5159
return null;
5260
}
5361
}

0 commit comments

Comments
 (0)