Skip to content

Commit

Permalink
Fixes #8863 - Provide a possibility to name virtual threads (#8903)
Browse files Browse the repository at this point in the history
* Fixes #8863 - Provide a possibility to name virtual threads

Reworked the VirtualThreads APIs to be based on `Executor` rather than just `boolean`.
Introduced Jetty module `threadpool-virtual-preview`.

Signed-off-by: Simone Bordet <[email protected]>
  • Loading branch information
sbordet authored Nov 21, 2022
1 parent 88ea1e8 commit 83154b4
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,16 @@ public boolean tryExecute(Runnable task)
}

@Override
public boolean isUseVirtualThreads()
public Executor getVirtualThreadsExecutor()
{
return VirtualThreads.isUseVirtualThreads(_executor);
return VirtualThreads.getVirtualThreadsExecutor(_executor);
}

@Override
public void setUseVirtualThreads(boolean useVirtualThreads)
public void setVirtualThreadsExecutor(Executor executor)
{
if (_executor instanceof VirtualThreads.Configurable)
((VirtualThreads.Configurable)_executor).setUseVirtualThreads(useVirtualThreads);
((VirtualThreads.Configurable)_executor).setVirtualThreadsExecutor(executor);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">

<Configure>
<New id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="name" property="jetty.threadPool.namePrefix" />
<Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
<Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
<Set name="reservedThreads" type="int"><Property name="jetty.threadPool.reservedThreads" default="-1"/></Set>
<Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
<Set name="detailedDump" type="boolean"><Property name="jetty.threadPool.detailedDump" default="false"/></Set>
<Get id="namePrefix" name="name" />
<Call class="java.lang.Thread" name="ofVirtual">
<Call class="java.lang.Thread$Builder" name="name">
<Arg>
<Property name="jetty.threadPool.virtual.namePrefix">
<Default><Ref refid="namePrefix" />-virtual-</Default>
</Property>
</Arg>
<Arg type="long">0</Arg>
<Call class="java.lang.Thread$Builder" name="allowSetThreadLocals">
<Arg type="boolean"><Property name="jetty.threadPool.virtual.allowSetThreadLocals" default="true" /></Arg>
<Call class="java.lang.Thread$Builder" name="inheritInheritableThreadLocals">
<Arg type="boolean"><Property name="jetty.threadPool.virtual.inheritInheritableThreadLocals" default="false" /></Arg>
<Call id="virtualThreadFactory" class="java.lang.Thread$Builder" name="factory" />
</Call>
</Call>
</Call>
</Call>
<Call name="setVirtualThreadsExecutor">
<Arg>
<Call class="java.util.concurrent.Executors" name="newThreadPerTaskExecutor">
<Arg><Ref refid="virtualThreadFactory" /></Arg>
</Call>
</Arg>
</Call>
</New>

<Call class="org.slf4j.LoggerFactory" name="getLogger">
<Arg>org.eclipse.jetty</Arg>
<Call name="warn">
<Arg>Virtual threads are a Java Preview Feature, support may be limited.</Arg>
</Call>
</Call>
</Configure>
3 changes: 2 additions & 1 deletion jetty-server/src/main/config/etc/jetty-threadpool.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
<!-- for all configuration that may be set here. -->
<!-- =========================================================== -->
<New id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="name" property="jetty.threadPool.namePrefix" />
<Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
<Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
<Set name="reservedThreads" type="int"><Property name="jetty.threadPool.reservedThreads" default="-1"/></Set>
<Set name="useVirtualThreads" type="boolean"><Property name="jetty.threadPool.useVirtualThreads" default="false"/></Set>
<Set name="useVirtualThreads" type="boolean"><Property deprecated="jetty.threadPool.useVirtualThreads" default="false"/></Set>
<Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
<Set name="detailedDump" type="boolean"><Property name="jetty.threadPool.detailedDump" default="false"/></Set>
</New>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[description]
Enables and configures the Server ThreadPool with support for virtual threads.

[exec]
--enable-preview

[depends]
logging

[provides]
threadpool

[xml]
etc/jetty-threadpool-virtual-preview.xml

[ini-template]
## Platform threads name prefix.
#jetty.threadPool.namePrefix=qtp<hashCode>

## Minimum number of pooled threads.
#jetty.threadPool.minThreads=10

## Maximum number of pooled threads.
#jetty.threadPool.maxThreads=200

## Number of reserved threads (-1 for heuristic).
#jetty.threadPool.reservedThreads=-1

## Thread idle timeout (in milliseconds).
#jetty.threadPool.idleTimeout=60000

## Whether to output a detailed dump.
#jetty.threadPool.detailedDump=false

## Virtual threads name prefix.
#jetty.threadPool.virtual.namePrefix=qtp<hashCode>-virtual-

## Whether virtual threads are allowed to set thread locals.
#jetty.threadPool.virtual.allowSetThreadLocals=true

## Whether virtual threads inherits the values of inheritable thread locals.
#jetty.threadPool.virtual.allowSetThreadLocals=true
7 changes: 7 additions & 0 deletions jetty-server/src/main/config/modules/threadpool.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ Enables and configures the Server ThreadPool.
[depends]
logging

[provides]
threadpool|default

[xml]
etc/jetty-threadpool.xml

[ini-template]
## Thread name prefix.
#jetty.threadPool.namePrefix=qtp<hashCode>

## Minimum number of pooled threads.
#jetty.threadPool.minThreads=10

Expand All @@ -18,6 +24,7 @@ etc/jetty-threadpool.xml
#jetty.threadPool.reservedThreads=-1

## Whether to use virtual threads, if the runtime supports them.
## Deprecated, use Jetty module 'threadpool-virtual-preview' instead.
#jetty.threadPool.useVirtualThreads=false

## Thread idle timeout (in milliseconds).
Expand Down
71 changes: 60 additions & 11 deletions jetty-util/src/main/java/org/eclipse/jetty/util/VirtualThreads.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* and, if virtual threads are supported, to start virtual threads.</p>
*
* @see #areSupported()
* @see #executeOnVirtualThread(Runnable)
* @see #getVirtualThreadsExecutor(Executor)
* @see #isVirtualThread()
*/
public class VirtualThreads
Expand Down Expand Up @@ -58,6 +58,11 @@ private static Method probeIsVirtualThread()
}
}

private static Method getIsVirtualThreadMethod()
{
return isVirtualThread;
}

private static void warn()
{
LOG.warn("Virtual thread support is not available (or not enabled via --enable-preview) in the current Java runtime ({})", System.getProperty("java.version"));
Expand All @@ -78,14 +83,16 @@ public static boolean areSupported()
*
* @param task the task to execute in a virtual thread
* @see #areSupported()
* @deprecated use {@link #getVirtualThreadsExecutor(Executor)} instead
*/
@Deprecated(forRemoval = true)
public static void executeOnVirtualThread(Runnable task)
{
try
{
if (LOG.isDebugEnabled())
LOG.debug("Starting in virtual thread: {}", task);
executor.execute(task);
getDefaultVirtualThreadsExecutor().execute(task);
}
catch (Throwable x)
{
Expand All @@ -101,7 +108,7 @@ public static boolean isVirtualThread()
{
try
{
return (Boolean)isVirtualThread.invoke(Thread.currentThread());
return (Boolean)getIsVirtualThreadMethod().invoke(Thread.currentThread());
}
catch (Throwable x)
{
Expand All @@ -110,6 +117,25 @@ public static boolean isVirtualThread()
}
}

/**
* @return a default virtual thread per task {@code Executor}
*/
public static Executor getDefaultVirtualThreadsExecutor()
{
return executor;
}

/**
* @param executor the {@code Executor} to obtain a virtual threads {@code Executor} from
* @return a virtual threads {@code Executor} obtained from the given {@code Executor}
*/
public static Executor getVirtualThreadsExecutor(Executor executor)
{
if (executor instanceof Configurable)
return ((Configurable)executor).getVirtualThreadsExecutor();
return null;
}

/**
* <p>Tests whether the given executor implements {@link Configurable} and
* it has been configured to use virtual threads.</p>
Expand All @@ -121,39 +147,62 @@ public static boolean isVirtualThread()
public static boolean isUseVirtualThreads(Executor executor)
{
if (executor instanceof Configurable)
return ((Configurable)executor).isUseVirtualThreads();
return ((Configurable)executor).getVirtualThreadsExecutor() != null;
return false;
}

/**
* <p>Implementations of this interface can be configured to use virtual threads.</p>
* <p>Whether virtual threads are actually used depends on whether the runtime
* supports virtual threads and, if the runtime supports them, whether they are
* configured to be used via {@link #setUseVirtualThreads(boolean)}.</p>
* configured to be used via {@link #setVirtualThreadsExecutor(Executor)}.</p>
*/
public interface Configurable
{
/**
* @return whether to use virtual threads
* @return the {@code Executor} to use to execute tasks in virtual threads
*/
default boolean isUseVirtualThreads()
default Executor getVirtualThreadsExecutor()
{
return false;
return null;
}

/**
* @param useVirtualThreads whether to use virtual threads
*
* @param executor the {@code Executor} to use to execute tasks in virtual threads
* @throws UnsupportedOperationException if the runtime does not support virtual threads
* @see #areSupported()
*/
default void setUseVirtualThreads(boolean useVirtualThreads)
default void setVirtualThreadsExecutor(Executor executor)
{
if (useVirtualThreads && !VirtualThreads.areSupported())
if (executor != null && !VirtualThreads.areSupported())
{
warn();
throw new UnsupportedOperationException();
}
}

/**
* @return whether to use virtual threads
* @deprecated use {@link #getVirtualThreadsExecutor()} instead
*/
@Deprecated(forRemoval = true)
default boolean isUseVirtualThreads()
{
return getVirtualThreadsExecutor() != null;
}

/**
* @param useVirtualThreads whether to use virtual threads
* @throws UnsupportedOperationException if the runtime does not support virtual threads
* @see #areSupported()
* @deprecated use {@link #setVirtualThreadsExecutor(Executor)} instead
*/
@Deprecated(forRemoval = true)
default void setUseVirtualThreads(boolean useVirtualThreads)
{
setVirtualThreadsExecutor(useVirtualThreads ? executor : null);
}
}

private VirtualThreads()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -47,7 +48,7 @@ public class ExecutorThreadPool extends ContainerLifeCycle implements ThreadPool
private int _priority = Thread.NORM_PRIORITY;
private boolean _daemon;
private boolean _detailedDump;
private boolean _useVirtualThreads;
private Executor _virtualThreadsExecutor;

public ExecutorThreadPool()
{
Expand Down Expand Up @@ -271,18 +272,18 @@ public boolean isLowOnThreads()
}

@Override
public boolean isUseVirtualThreads()
public Executor getVirtualThreadsExecutor()
{
return _useVirtualThreads;
return _virtualThreadsExecutor;
}

@Override
public void setUseVirtualThreads(boolean useVirtualThreads)
public void setVirtualThreadsExecutor(Executor executor)
{
try
{
VirtualThreads.Configurable.super.setUseVirtualThreads(useVirtualThreads);
_useVirtualThreads = useVirtualThreads;
VirtualThreads.Configurable.super.setVirtualThreadsExecutor(executor);
_virtualThreadsExecutor = executor;
}
catch (UnsupportedOperationException ignored)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -111,7 +112,7 @@ public class QueuedThreadPool extends ContainerLifeCycle implements ThreadFactor
private int _lowThreadsThreshold = 1;
private ThreadPoolBudget _budget;
private long _stopTimeout;
private boolean _useVirtualThreads;
private Executor _virtualThreadsExecutor;

public QueuedThreadPool()
{
Expand Down Expand Up @@ -515,18 +516,18 @@ public void setLowThreadsThreshold(int lowThreadsThreshold)
}

@Override
public boolean isUseVirtualThreads()
public Executor getVirtualThreadsExecutor()
{
return _useVirtualThreads;
return _virtualThreadsExecutor;
}

@Override
public void setUseVirtualThreads(boolean useVirtualThreads)
public void setVirtualThreadsExecutor(Executor executor)
{
try
{
VirtualThreads.Configurable.super.setUseVirtualThreads(useVirtualThreads);
_useVirtualThreads = useVirtualThreads;
VirtualThreads.Configurable.super.setVirtualThreadsExecutor(executor);
_virtualThreadsExecutor = executor;
}
catch (UnsupportedOperationException ignored)
{
Expand Down
Loading

0 comments on commit 83154b4

Please sign in to comment.