网易面试:SpringBoot如何开启虚拟线程?

简介: 虚拟线程(Virtual Thread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小、资源利用率更高,是 Java 并发编程领域的一项重要创新。> PS:虚拟线程正式发布于 Java 长期支持版(Long Term Suort,LTS)Java 21(也就是 JDK 21)。虚拟线程是一种在 Java 虚拟机(JVM)层面实现的逻辑线程,不直接和操作系统的物理线程一一对应,因此它可以减少上下文切换所带来的性能开销。操作系统线程、普通线程(Java 线程)和虚拟线程的关系如下:![image.png](https:

虚拟线程(Virtual Thread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小、资源利用率更高,是 Java 并发编程领域的一项重要创新。

PS:虚拟线程正式发布于 Java 长期支持版(Long Term Suort,LTS)Java 21(也就是 JDK 21)。

虚拟线程是一种在 Java 虚拟机(JVM)层面实现的逻辑线程,不直接和操作系统的物理线程一一对应,因此它可以减少上下文切换所带来的性能开销。

操作系统线程、普通线程(Java 线程)和虚拟线程的关系如下:
image.png

1.虚拟线程使用

虚拟线程的创建有以下 4 种方式:

  1. Thread.startVirtualThread(Runnable task)
  2. Thread.ofVirtual().unstarted(Runnable task)
  3. Thread.ofVirtual().factory()
  4. Executors.newVirtualThreadPerTaskExecutor()

具体使用如下。

1.1 startVirtualThread

创建虚拟线程,并直接启动执行任务:

// 创建并启动虚拟线程
Thread.startVirtualThread(() -> {
   
   
    System.out.println("Do virtual thread.");
});

1.2 unstarted

只创建虚拟线程,但不直接启动(创建之后通过 start 启动):

// 创建虚拟线程
Thread vt = Thread.ofVirtual().unstarted(()->{
   
   
    System.out.println("Do virtual thread.");
});
// 运行虚拟线程
vt.start();

1.3 factory

先创建虚拟线程工厂,然后再使用工厂创建虚拟线程,之后再调用 start() 方法进行执行:

// 创建虚拟线程工厂
ThreadFactory tf = Thread.ofVirtual().factory();
// 创建虚拟线程
Thread vt = tf.newThread(()->{
   
   
    System.out.println("Do virtual thread.");
});
// 运行虚拟线程
vt.start();

1.4 newVirtualThreadPerTaskExecutor

创建虚拟线程池:

// 创建一个支持虚拟线程的线程池
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(()->{
   
   
    System.out.println("Do virtual thread.");
});

2.虚拟线程 VS 普通线程

虚拟线程和普通线程的区别主要体现在以下几点:

  1. 普通线程是和操作系统的物理线程是一一对应的,而虚拟线程是 JVM 层面的逻辑线程,并不和操作系统的物理线程一一对应,它可以看作是轻量级的线程。
  2. 普通线程默认创建的是用户线程(而守护线程),而虚拟线程是守护线程,并且其守护线程的属性不能被修改,如果修改就会报错,如下图所示:

  1. 虚拟线程由 JVM 调度和使用,避免了普通线程频繁切换的性能开销,所以相比于普通的线程来说,运行效率更高。

    3.SpringBoot开启虚拟线程

    以最新版的 Spring Boot 3.x 为例,我们开启虚拟线程很简单,只需要在 Spring Boot 配置文件中设置“spring.threads.virtual.enabled”为“true”即可开启,以 application.yml 为例,启用虚拟线程配置如下:
    spring:
    threads:
     virtual:
       enabled: true # 启用虚拟线程
    
    这样 Spinrg Boot 在启动 Tomcat 容器时,会使用一个虚拟线程执行器来代表原有的平台线程池。

    PS:这里是虚拟线程执行器,不是虚拟线程池。

如果以上配置未生效的话,还可以通过修改 Tomcat 配置类,让其使用虚拟线程来处理每一个请求,配置代码如下:

import java.util.concurrent.Executors;

import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TomcatConfiguration {
   
   
    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
   
   
        return protocolHandler -> {
   
   
            // 使用虚拟线程来处理每一个请求
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
        };
    }
}

4.异步任务开启虚拟线程

如果你想为 Spring Boot 中的异步任务 @Async 也配置虚拟线程的话,可以在 AsyncConfigurer 配置类中设置,配置代码如下:

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync  // 开启异步任务
public class AsyncTaskConfiguration implements AsyncConfigurer {
   
   
    @Override
    public Executor getAsyncExecutor() {
   
   
        return new TaskExecutorAdapter(Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("virtual-async#", 1).factory()));
    }
}

课后思考

说说虚拟线程的底层实现?有了虚拟线程后还需要虚拟线程池吗?为什么?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关文章
|
2月前
|
Oracle Java API
虚拟线程:Java的新利器?
作者通过本文梳理了自己对虚拟线程的理解,顺便捋一捋Java线程的过去、现在和未来。ps:写这篇文章的时候,Java 19刚刚发布,而现在Java 21已经正式GA了,不过虚拟线程的API和底层实现并没有什么变化。
|
18天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
172 37
|
18天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
18天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
19天前
|
消息中间件 前端开发 NoSQL
面试官:线程池遇到未处理的异常会崩溃吗?
面试官:线程池遇到未处理的异常会崩溃吗?
57 3
面试官:线程池遇到未处理的异常会崩溃吗?
|
20天前
|
消息中间件 存储 前端开发
面试官:说说停止线程池的执行流程?
面试官:说说停止线程池的执行流程?
34 2
面试官:说说停止线程池的执行流程?
|
12天前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
23天前
|
消息中间件 前端开发 NoSQL
面试官:如何实现线程池任务编排?
面试官:如何实现线程池任务编排?
24 1
面试官:如何实现线程池任务编排?
|
2月前
|
Java 调度 开发者
Java 神秘新成员 —— 虚拟线程究竟是什么?它又能解开哪些编程痛点之谜?
【8月更文挑战第23天】Java虚拟线程是一种轻量级执行线程,由Java运行时管理,相较于传统操作系统线程,其创建和管理成本更低。基于用户模式线程概念,Java应用程序无需依赖OS即可实现高度并发。虚拟线程数量可远超传统线程,有效提升多核处理器利用率和并发性能。它解决了传统Java线程模型中创建成本高、调度开销大及I/O阻塞等问题,极大提高了程序的并发性和响应速度。
19 1
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。