Spring Boot 3.x 虚拟线程实战:别再傻傻用线程池了
·
上周在项目里遇到个问题,折腾了两天终于搞定了
我们有个IO密集型的接口,并发一上来线程池就扛不住。试过加线程数,效果不明显;换过不同队列策略,也不行。后来听说Java 21的虚拟线程专门解决这类问题,就决定试试。
虚拟线程到底是什么
先说结论:虚拟线程是JVM层面的轻量级线程,由调度器映射到少量平台线程上运行。
跟传统线程池最大的区别:
| 特性 | 平台线程 | 虚拟线程 |
|---|---|---|
| 创建成本 | ~1KB栈内存 | ~几百字节 |
| 百万级创建 | OOM | 没问题 |
| 阻塞操作 | 占用平台线程 | 自动卸载 |
一句话:如果你的业务大部分时间都在等DB、等HTTP、等MQ,虚拟线程就是为你准备的。
Spring Boot 3 开启虚拟线程
就这么一行?对,但实际用起来有不少细节要注意。
完整可运行代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<groupId>com.example</groupId>
<artifactId>virtual-thread-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8080
spring:
threads:
virtual:
enabled: true
主启动类
package com.example.vt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class VtApp {
public static void main(String[] args) {
SpringApplication.run(VtApp.class, args);
}
}
IO密集型服务模拟
package com.example.vt.service;
import org.springframework.stereotype.Service;
import java.util.concurrent.*;
import java.util.ArrayList;
@Service
public class IoService {
public String dbQuery(String id, int delayMs) {
boolean vt = Thread.currentThread().isVirtual();
try { Thread.sleep(delayMs); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); return " interrupted"; }
return "[vt=" + vt + "] DB-" + id + "-ok";
}
public CompletableFuture<String> parallelQuery(int count) {
var futures = new ArrayList<CompletableFuture<String>>();
for (int i = 0; i < count; i++) {
final int idx = i;
futures.add(CompletableFuture.supplyAsync(() -> dbQuery("q-" + idx, 30 + idx % 5 * 15)));
}
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> { StringBuilder sb = new StringBuilder();
for (var f : futures) sb.append(f.join()).append("|"); return sb.toString(); });
}
}
性能对比测试
package com.example.vt.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
@Service
public class BenchService {
@Autowired private IoService ioService;
public String runCompare(int taskCount) {
var r = new StringBuilder();
r.append("===== 对比测试 (" + taskCount + "任务) =====\n");
int[] sizes = {4, 8, 16, 32, 64};
for (int s : sizes) {
var pool = Executors.newFixedThreadPool(s);
var start = Instant.now();
var futs = new ArrayList<Future<String>>();
for (int i = 0; i < taskCount; i++) {
final int idx = i;
futs.add(pool.submit(() -> ioService.dbQuery("tp-" + idx, 30)));
}
for (var f : futs) { try { f.get(); } catch(Exception e){} }
pool.shutdown();
r.append("[ThreadPool-" + s + "] " + taskCount + "任务 -> " +
Duration.between(start, Instant.now()).toMillis() + "ms\n");
}
var vtp = Executors.newVirtualThreadPerTaskExecutor();
var start2 = Instant.now();
var vfuts = new ArrayList<Future<String>>();
for (int i = 0; i < taskCount; i++) {
final int idx = i;
vfuts.add(vtp.submit(() -> ioService.dbQuery("vt-" + idx, 30)));
}
for (var f : vfuts) { try { f.get(); } catch(Exception e){} }
vtp.close();
r.append("[VirtualThreads] " + taskCount + "任务 -> " +
Duration.between(start2, Instant.now()).toMillis() + "ms\n");
return r.toString();
}
}
REST控制器
package com.example.vt.controller;
import com.example.vt.service.BenchService;
import com.example.vt.service.IoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.CompletableFuture;
import java.util.Map;
@RestController
@RequestMapping("/api/demo")
public class DemoCtrl {
@Autowired private IoService ioService;
@Autowired private BenchService benchService;
@GetMapping("/io/{id}")
public ResponseEntity<?> singleIo(@PathVariable String id) {
return ResponseEntity.ok(Map.of(
"id", id, "data", ioService.dbQuery(id, 80),
"isVirtual", Thread.currentThread().isVirtual(),
"thread", Thread.currentThread().getName()
));
}
@GetMapping("/parallel-io")
public CompletableFuture<ResponseEntity<?>> parallelIo(@RequestParam(defaultValue="20") int count) {
return ioService.parallelQuery(count).thenApply(ResponseEntity::ok);
}
@GetMapping("/bench")
public ResponseEntity<?> bench(@RequestParam(defaultValue="500") int n) {
return ResponseEntity.ok(benchService.runCompare(n));
}
}
测试类
package com.example.vt;
import com.example.vt.service.IoService;
import com.example.vt.service.BenchService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.*;
@SpringBootTest
class VtAppTests {
@Autowired private IoService ioService;
@Autowired private BenchService benchService;
@Test void testDbQuery() { assertThat(ioService.dbQuery("test", 10)).contains("test"); }
@Test void testParallel() throws Exception { assertThat(ioService.parallelQuery(15).get()).contains("DB"); }
@Test void testBench() { System.out.println(benchService.runCompare(200)); }
}
我踩过的坑
坑1:synchronized会钉死平台线程
虚拟线程遇到synchronized会钉住底层平台线程。所以:
// 错误做法
public synchronized void badMethod() { ... }
// 正确做法 — 用ReentrantLock替代
private final ReentrantLock lock = new ReentrantLock();
public void goodMethod() { lock.lock(); try {} finally { lock.unlock(); } }
坑2:不要池化虚拟线程
// 不要这样
Executors.newFixedThreadPool(200, factory);
// 这样就好
Executors.newVirtualThreadPerTaskExecutor();
坑3:数据库连接池要调大
因为虚拟线程支撑更多并发请求,连接池可能成为新瓶颈。
总结
虚拟线程不是银弹,但在IO密集型场景确实能简化并发模型。核心优势就三个字:不用调参。
环境要求:JDK 21+, Spring Boot 3.2+
完整代码:以上可直接运行
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)