Skip to content

Commit

Permalink
Fixes #11353 named virtual thread executor (#11430)
Browse files Browse the repository at this point in the history
Introduced `VirtualThreads.getNamedVirtualThreadsExecutor(String namePrefix)` to allow users/libraries to name virtual threads if they so wish.
  • Loading branch information
danishnawab authored Feb 21, 2024
1 parent 8fec190 commit f860175
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@

package org.eclipse.jetty.test.client.transport;

import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.client.ContentResponse;
Expand Down Expand Up @@ -62,12 +59,7 @@ public boolean handle(Request request, Response response, Callback callback)
ThreadPool threadPool = server.getThreadPool();
if (threadPool instanceof VirtualThreads.Configurable)
{
// CAUTION: Java 19 specific reflection code, might change in future Java versions.
Object builder = Thread.class.getMethod("ofVirtual").invoke(null);
Class<?> builderClass = Arrays.stream(Thread.class.getClasses()).filter(klass -> klass.getName().endsWith("$Builder")).findFirst().orElseThrow();
builder = builderClass.getMethod("name", String.class, long.class).invoke(builder, virtualThreadsName, 0L);
ThreadFactory factory = (ThreadFactory)builderClass.getMethod("factory").invoke(builder);
Executor virtualThreadsExecutor = (Executor)Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class).invoke(null, factory);
Executor virtualThreadsExecutor = VirtualThreads.getNamedVirtualThreadsExecutor(virtualThreadsName);
((VirtualThreads.Configurable)threadPool).setVirtualThreadsExecutor(virtualThreadsExecutor);
}
server.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -117,6 +118,29 @@ public static boolean isVirtualThread()
}
}

/**
* Get a virtual threads {@code Executor} that names the virtual threads according to the provided name prefix.
* While named virtual threads enable observability they do also incur a minor performance penalty.
*
* @param namePrefix the prefix to use for the name of the virtual threads
* @return a virtual threads {@code Executor} that will name the virtual threads according to the provided name prefix.
*/
public static Executor getNamedVirtualThreadsExecutor(String namePrefix)
{
try
{
Class<?> builderClass = Class.forName("java.lang.Thread$Builder");
Object threadBuilder = Thread.class.getMethod("ofVirtual").invoke(null);
threadBuilder = builderClass.getMethod("name", String.class, long.class).invoke(threadBuilder, namePrefix, 0L);
ThreadFactory factory = (ThreadFactory)builderClass.getMethod("factory").invoke(threadBuilder);
return (Executor)Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class).invoke(null, factory);
}
catch (Throwable x)
{
return null;
}
}

/**
* Get a default virtual thread per task {@code Executor}.
* @return a default virtual thread per task {@code Executor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@
package org.eclipse.jetty.ee10.test.client.transport;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

Expand Down Expand Up @@ -70,12 +67,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
ThreadPool threadPool = server.getThreadPool();
if (threadPool instanceof VirtualThreads.Configurable)
{
// CAUTION: Java 19 specific reflection code, might change in future Java versions.
Object builder = Thread.class.getMethod("ofVirtual").invoke(null);
Class<?> builderClass = Arrays.stream(Thread.class.getClasses()).filter(klass -> klass.getName().endsWith("$Builder")).findFirst().orElseThrow();
builder = builderClass.getMethod("name", String.class, long.class).invoke(builder, virtualThreadsName, 0L);
ThreadFactory factory = (ThreadFactory)builderClass.getMethod("factory").invoke(builder);
Executor virtualThreadsExecutor = (Executor)Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class).invoke(null, factory);
Executor virtualThreadsExecutor = VirtualThreads.getNamedVirtualThreadsExecutor(virtualThreadsName);
((VirtualThreads.Configurable)threadPool).setVirtualThreadsExecutor(virtualThreadsExecutor);
}
server.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@
package org.eclipse.jetty.ee9.test.client.transport;

import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

Expand Down Expand Up @@ -70,12 +67,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
ThreadPool threadPool = server.getThreadPool();
if (threadPool instanceof VirtualThreads.Configurable)
{
// CAUTION: Java 19 specific reflection code, might change in future Java versions.
Object builder = Thread.class.getMethod("ofVirtual").invoke(null);
Class<?> builderClass = Arrays.stream(Thread.class.getClasses()).filter(klass -> klass.getName().endsWith("$Builder")).findFirst().orElseThrow();
builder = builderClass.getMethod("name", String.class, long.class).invoke(builder, virtualThreadsName, 0L);
ThreadFactory factory = (ThreadFactory)builderClass.getMethod("factory").invoke(builder);
Executor virtualThreadsExecutor = (Executor)Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class).invoke(null, factory);
Executor virtualThreadsExecutor = VirtualThreads.getNamedVirtualThreadsExecutor(virtualThreadsName);
((VirtualThreads.Configurable)threadPool).setVirtualThreadsExecutor(virtualThreadsExecutor);
}
server.start();
Expand Down

0 comments on commit f860175

Please sign in to comment.