Skip to content

RunOnVirtualThread has some unexpected cost due to the default VT builder #51201

@franz1981

Description

@franz1981

Description

Image

This has been obtained by running https://github.com/quarkusio/spring-quarkus-perf-comparison adding RunOnVirtualThread on the quarkus's rest endpoint.

Method ofVirtual = Thread.class.getMethod("ofVirtual");
Object vtb = ofVirtual.invoke(VirtualThreadsRecorder.class);
Class<?> vtbClass = Class.forName("java.lang.Thread$Builder$OfVirtual");
// .name()
if (prefix != null) {
Method name = vtbClass.getMethod("name", String.class, long.class);
vtb = name.invoke(vtb, prefix, 0);
}
// .uncaughtExceptionHandler()
Method uncaughtHandler = vtbClass.getMethod("uncaughtExceptionHandler", Thread.UncaughtExceptionHandler.class);
vtb = uncaughtHandler.invoke(vtb, new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.errorf(e, "Thread %s threw an uncaught exception:", t);
}
});
// .factory()
Method factory = vtbClass.getMethod("factory");
ThreadFactory tf = (ThreadFactory) factory.invoke(vtb);
return (ExecutorService) Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class)
.invoke(VirtualThreadsRecorder.class, tf);
}

This shows two things:

  1. https://github.com/openjdk/jdk25u/blob/8fd9a739c895d7f0f860a8170d22cb50574abc79/src/java.base/share/classes/java/lang/ThreadBuilders.java#L312 this is not correctly optimizing the indy call to produce the builder name - making it a much slower reflective one
  2. the new virtual thread has inherited map: do we really need that? The doc says "Thread also supports InheritableThreadLocal variables that are thread local variables that are inherited at thread creation time from the parent Thread"

The second seems ok to just disable TL inheritance on the builder, if we don't need it
Whilst for the first, I'm checking if is a perf fissue we can do anything about: my guess is that we can roll our own naming mechanism i.e. just setting a fixed name ourself(e.g relying on https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Thread.Builder.OfVirtual.html#name(java.lang.String)) on the builder, but it's likely a JDK bug while using VarHandle (passing an int 1 instead of a long been a polymorphic signature).

Implementation ideas

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions