基本介绍
使用ThreadPerTaskExecutor时,每一个任务都会创建一个线程,理想情况下可以创建无限多线程。 主要为jdk21提供的虚拟线程使用的。虚拟线程比较轻量级,平台线程比较重。
基础使用
通过Executors.newVirtualThreadPerTaskExecutor();创建一个虚拟线程ThreadPerTaskExecutor,用于提交任务给虚拟线程执行。
ExecutorService executor= Executors.newVirtualThreadPerTaskExecutor();
executor.submit(()->{
});
源码阅读
ThreadPerTaskExecutor
查看ThreadPerTaskExecutor的submit方法可以知道目前Executor的流程为创建了一个ThreadBoundFuture然后执行start直接通过future对应的virtual thread进行执行task。 这里有个细节,在执行虚拟线程之前会放在set里,执行完了会删除thread。即同一时刻同一个thread只能执行一个。 java.util.concurrent.ThreadPerTaskExecutor#submit(java.util.concurrent.Callable)
public <T> Future<T> submit(Callable<T> task) {
Objects.requireNonNull(task);
ensureNotShutdown();
var future = new ThreadBoundFuture<>(this, task);
Thread thread = future.thread();
start(thread);
return future;
}
在start方法里会执行JLA.start(thread, this);来执行Thread.start方法启动线程
private void start(Thread thread) {
assert thread.getState() == Thread.State.NEW;
// 添加对应线程到set
threads.add(thread);
boolean started = false;
try {
if (state == RUNNING) {
// 执行线程的start
JLA.start(thread, this);
started = true;
}
} finally {
if (!started) {
// 从set移除对应线程
taskComplete(thread);
}
}
// throw REE if thread not started and no exception thrown
if (!started) {
throw new RejectedExecutionException();
}
}
JavaLangAccess
在上面的start方法里通过执行JLA.start(thread, this);执行线程。JLA的定义为
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
在JavaLangAccess的start里执行了线程的start方法。此时thread有两种可能:Thread、VirtualThread
jdk.internal.access.JavaLangAccess#start
public void start(Thread thread, ThreadContainer container) {
thread.start(container);
}
ThreadBoundFuture
ThreadBoundFuture会通过ThreadPerTaskExecutor创建一个虚拟线程
ThreadBoundFuture(ThreadPerTaskExecutor executor, Callable<T> task) {
super(task);
this.executor = executor;
this.thread = executor.newThread(this);
}
ThreadPerTaskExecutor的newThread会执行VirtualThreadFactory的newThread来创建一个虚拟线程 java.util.concurrent.ThreadPerTaskExecutor#newThread
private Thread newThread(Runnable task) {
Thread thread = factory.newThread(task);
if (thread == null)
throw new RejectedExecutionException();
return thread;
}
VirtualThreadFactory
VirtualThreadFactory的newThread会执行newVirtualThread创建一个虚拟线程
public Thread newThread(Runnable task) {
Objects.requireNonNull(task);
String name = nextThreadName();
Thread thread = newVirtualThread(scheduler, name, characteristics(), task);
UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
if (uhe != null)
thread.uncaughtExceptionHandler(uhe);
return thread;
}
在newVirtualThread会通过ContinuationSupport.isSupported()判断jvm是否支持虚拟线程,如果不支持就创建一个BoundVirtualThread直接当前线程执行对应task的run方法,否则创建一个VirtualThread,让挂载当前虚拟线程,执行虚拟线程,然后卸载虚拟线程
static Thread newVirtualThread(Executor scheduler,
String name,
int characteristics,
Runnable task) {
if (ContinuationSupport.isSupported()) {
return new VirtualThread(scheduler, name, characteristics, task);
} else {
if (scheduler != null)
throw new UnsupportedOperationException();
return new BoundVirtualThread(name, characteristics, task);
}
}
BoundVirtualThread
BoundVirtualThread直接执行task.run();在当前线程执行任务
public void run() {
// run is specified to do nothing when Thread is a virtual thread
if (Thread.currentThread() == this && !runInvoked) {
runInvoked = true;
task.run();
}
}
VirtualThread
VirtualThread执行挂载、执行、卸载
private void run(Runnable task) {
assert state == RUNNING;
// first mount
mount();
notifyJvmtiStart();
// emit JFR event if enabled
if (VirtualThreadStartEvent.isTurnedOn()) {
var event = new VirtualThreadStartEvent();
event.javaThreadId = threadId();
event.commit();
}
Object bindings = scopedValueBindings();
try {
runWith(bindings, task);
} catch (Throwable exc) {
dispatchUncaughtException(exc);
} finally {
try {
// pop any remaining scopes from the stack, this may block
StackableScope.popAll();
// emit JFR event if enabled
if (VirtualThreadEndEvent.isTurnedOn()) {
var event = new VirtualThreadEndEvent();
event.javaThreadId = threadId();
event.commit();
}
} finally {
// last unmount
notifyJvmtiEnd();
unmount();
// final state
setState(TERMINATED);
}
}
}