Java中的虚线程类似Go中的协程,简单来说可以通过同步编程的方式来达到异步编程模式的效果,具体的技术细节可以参考
https://blog.csdn.net/nyzzht123/article/details/132270674
https://openjdk.org/jeps/444
基础环境
虚线程最早在JDK19中推出,但是是preview的状态,正式版本是在JDK21中推出,如果你需要体验虚线程,可以在pom中进行如下配置
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
如果你当前版本低于21,大于等于19,需要增加 --enable-preview
参数来启动preview的功能
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>19</source>
<target>19</target>
<compilerArgs>
--enable-preview
</compilerArgs>
</configuration>
</plugin>
线程池配置
我们在web应用中常用的线程池有两类,一类是tomcat的线程池,另一类是后台异步任务的线程池,可以通过以下方式来创建
@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
public AsyncTaskExecutor asyncTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}
@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
需要注意的是,因为虚线程不是真正的OS线程,它的创建和销毁的成本很低,因此并不需要复用,线程池的创建也就不需要指定coreThread, maxThread这些参数(具体细节可以参考虚线程简介)
日志输出
另外,除非在创建时指定,虚线程也没有名字,通过Thread#getName
的方式只能获取到一个空字符串,在日志打印中,有可能会获取不到。对于不同的日志组件有不同的解决方案
- 对于logback,需要将logback的版本升级到1.5.0以上
- 对于log4j2,可以通过打印tid的方式来解决