Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions src/java.base/share/classes/java/lang/Thread.java
Original file line number Diff line number Diff line change
Expand Up @@ -968,27 +968,42 @@ public interface VirtualThreadScheduler {
* @implSpec The default implementation creates a new virtual thread. It should
* be rare to override this method.
*
* @param builder the virtual thread builder
* @param preferredCarrier the preferred carrirer, can be {@code null}
* @param name the thread name, can be {@code null}
* @param characteristics the thread characteristics
* @param preferredCarrier the preferred carrier, can be {@code null}
* @param task the object to run when the thread executes
* @return the {@code VirtualThreadTask} that scheduler executes
* @throws UnsupportedOperationException if this is the built-in default scheduler
*
* @see <a href="Thread.html#inheritance">Inheritance when creating threads</a>
*/
default VirtualThreadTask newThread(Builder.OfVirtual builder,
default VirtualThreadTask newThread(String name, int characteristics,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

characteristics is JDK internal implementation default so cannot be exposed with the API like this.

@franz1981 franz1981 Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, I mentioned it in the first desc

I dislike to pass/intercepts raw VT parameters

That's what I meant 🙏

This is just a PoC to show the idea: currently there are different routes (builders/factories and raw VT start), and unify them to all go through the scheduler::newThread which uses a builder is not still right

Thread preferredCarrier,
Runnable task) {
Objects.requireNonNull(builder);
Objects.requireNonNull(task);
if (this == VirtualThread.builtinScheduler(false)) {
throw new UnsupportedOperationException();
}
var vbuilder = (ThreadBuilders.VirtualThreadBuilder) builder;
var vthread = (VirtualThread) vbuilder.unstarted(task, preferredCarrier);
var vthread = new VirtualThread(this, preferredCarrier, name, characteristics, task);
return vthread.virtualThreadTask();
}

/**
* Creates a new virtual thread using the given builder's configuration.
* Delegates to {@link #newThread(String, int, Thread, Runnable)}.
*
* @param builder the virtual thread builder
* @param preferredCarrier the preferred carrier, can be {@code null}
* @param task the object to run when the thread executes
* @return the {@code VirtualThreadTask} that scheduler executes
*/
default VirtualThreadTask newThread(Builder.OfVirtual builder,
Thread preferredCarrier,
Runnable task) {
Objects.requireNonNull(builder);
var vbuilder = (ThreadBuilders.VirtualThreadBuilder) builder;
return newThread(vbuilder.nextThreadName(), vbuilder.characteristics(),
preferredCarrier, task);
}

/**
* Schedules a task that becomes enabled for execution after the given delay.
*
Expand Down
11 changes: 11 additions & 0 deletions src/java.base/share/classes/java/lang/ThreadBuilders.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,12 +405,23 @@ public Thread newThread(Runnable task) {
/**
* Creates a new virtual thread to run the given task.
*/
// true when a custom scheduler is installed via implClass, JIT constant-folds
static final boolean CUSTOM_SCHEDULER =
VirtualThread.defaultScheduler() != VirtualThread.builtinScheduler(true);

private static Thread newVirtualThread(Thread.VirtualThreadScheduler scheduler,
Thread preferredCarrier,
String name,
int characteristics,
Runnable task) {
if (ContinuationSupport.isSupported()) {
// Route through the custom scheduler's newThread() when implClass is set.
// scheduler is non-null only with the legacy per-builder scheduler field,
// superseded by the global custom scheduler API (implClass).
if (scheduler == null && CUSTOM_SCHEDULER) {
return VirtualThread.defaultScheduler()
.newThread(name, characteristics, preferredCarrier, task).thread();
}
return new VirtualThread(scheduler, preferredCarrier, name, characteristics, task);
} else {
if (scheduler != null)
Expand Down