-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Description
This has been obtained by running https://github.com/quarkusio/spring-quarkus-perf-comparison adding RunOnVirtualThread on the quarkus's rest endpoint.
Lines 115 to 137 in 70552ed
| 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:
- 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
- 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
- remove naming v threads with a counter (see 8372410: ThreadFactory used by Thread.Builder::factory uses non-optimal VarHandle openjdk/jdk#28475)
- set on the builder to disable inherited thread locals (if not necessary eh!) - see https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html