Java19就是虚拟线程,ProjectLoom通过JEP425进入了JDK。从2022年9月的Java19开始,虚拟线程将可用作为预览功能。虚拟线程的目标是大大减少编写、维护和观察高吞吐量和高并发应用程序的工作量。ProjectLoom虚拟线程的使用显然不仅仅局限于直接减少内存占用或增加并发。虚拟线程的引入还提供了比只有平台线程可用时更多的选项。一、如何理解Java线程和虚拟线程我们常用的Java线程和系统内核线程之间存在着一一对应的关系,系统内核中的线程调度器负责调度Java线程。为了提高应用程序的性能,我们将添加越来越多的Java线程。系统在调度Java线程时,会占用大量资源来处理线程上下文切换。Java线程与系统内核线程尽管我们使用了各种线程池来最大化线程的性价比,但线程往往在CPU、网络或内存资源耗尽之前成为程序性能提升的瓶颈,由于硬件原因无法最大化利用硬件。表现。为了解决这个问题,Java19引入了虚拟线程。在Java19中,我们之前使用的线程称为平台线程,仍然和系统内核线程一一对应。大量(M)个虚拟线程运行在少量(N)个平台线程上(与操作系统线程一一对应)(M:N调度)。JVM会调度多个虚拟线程在一个平台线程上执行,一个平台线程同时只会执行一个虚拟线程。虚拟线程与平台线程二、SpringBoot3.0实战平台线程新建一个SpringBoot3项目。请注意,Java选择19和SpringBoot版本3.x。在SpringBoot下,我们使用平台线程是非常简单的。我们只需要通过@EnableAsync开启异步多线程支持,然后使用@Async注解标记需要多线程的任务即可。SpringBoot为我们提供了TaskExecutionAutoConfiguration和TaskExecutionProperties来配置线程池。让我们看看如果我们使用平台线程,代码会是什么样子。首先定义需要异步调用的任务:@Service@Slf4jpublicclassAsyncService{@AsyncpublicvoiddoSomething(inti){log.info("execute"+i+"times");}}然后,我们在入口类Multithreading中异步执行这个任务:@SpringBootApplication@EnableAsync@Slf4jpublicclassVirtualThreadsDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(VirtualThreadsDemoApplication.class,args);}@BeanCommandLineRunnercommandLineRunner(AsyncServiceasyncService){argreturn->{for(inti=0;i<100;i++){asyncService.doSomething(i);}};}}我们运行程序,发现SpringBoot默认的线程池中有8个平台线程为我们执行任务:平台线程池执行任务3,SpringBoot3.0实战虚拟线程SpringBoot自动配置TaskExecutionAutoConfiguration,@Lazy@Bean(name={APPLICATION_TASK_EXECUTOR_BEAN_NAME,AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME})@ConditionalOnMissingBean(ExecutorBean(Executor)publicThreadPoolTask??ExecutorapplicationTaskExecutor(TaskExecutorBuilderbuilder){返回builder.build();}SpringBoot配置了名为APPLICATION_TASK_EXECUTOR_BEAN_NAME(applicationTaskExecutor)的线程池执行器的Bean(ThreadPoolTask??Executor)供我们使用平台线程。如果我们要使用虚拟线程,我们也只需要定义APPLICATION_TASK_EXECUTOR_BEAN_NAME(applicationTaskExecutor)虚拟线程任务执行一周的Bean。我们在入口类中定义了这样一个Bean:@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)publicAsyncTaskExecutorasyncTaskExecutor(){returnnewTaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());}注意它为每个Executors.newVirtualThreadPerTaskExecutor(NewVirtualThreadPerTaskExecutorExecutor()创建一个Executor)任务启动一个新的虚拟线程。执行者创建的线程数是无限的。此时我们的SpringBoot程序会使用虚拟线程来创建线程,而不是默认的线程池。因为虚拟线程还是Java19的一个预览功能,所以我们需要为程序开启预览功能。build.gradle:plugins{id'java'id'org.springframework.boot'version'3.0.1'id'io.spring.dependency-management'version'1.1.0'}group='top.wisely'version='0.0.1-SNAPSHOT'sourceCompatibility='19'repositories{mavenCentral()}dependencies{//...}tasks.named('test'){useJUnitPlatform()}tasks.withType(JavaCompile){options.compilerArgs+="--enable-preview"}tasks.withType(JavaExec){jvmArgs+="--enable-preview"}此时执行我们的程序,发现线程一栏是空的,说明我们没有使用平台线程池,而是使用虚拟线程来执行。虚拟线程执行任务SpringBoot3.0支持Tomcat的虚拟线程,让Tomcat支持虚拟线程。您可以在程序中配置以下内容:@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)publicAsyncTaskExecutorasyncTaskExecutor(){returnnewTaskExecutorAdapter(Executors.newVirtualThreadPerTask));}@BeanpublicTomcatProtocolHandlerCustomizer>protocolHandlerVirtualThreadExecutorCustomizer(){returnprotocolHandler.->{returnprotocolHandler()setExecutor(Executors.newVirtualThreadPerTaskExecutor());多方面的支持。但不管怎么支持,我相信Spring给我们的是一种简单易用、学习曲线低的方法。参考资料:https://medium.com/javarevisited/how-to-use-java-19-virtual-threads-c16a32bad5f7https://spring.io/blog/2022/10/11/embracing-virtual-threads,文章来自:热爱科学的卫斯理,若转载本文,请今天联系热爱科学的卫斯理头条号。
