在后端开发中,“高并发”一直是 Java 程序员绕不开的话题。传统 Java 线程虽然使用简单,但在面对大量请求、数据库访问、远程服务调用时,线程资源很容易成为瓶颈。为了解决这个问题,Java 推出了一个重要项目:Project Loom。
Project Loom 的核心目标是:让 Java 能够以更低的成本创建和管理大量线程。
一、传统 Java 线程有什么问题?
在传统 Java 中,我们创建的 Thread 通常对应操作系统线程。
也就是说:
Java Thread ≈ OS Thread
操作系统线程并不便宜。每创建一个线程,都需要占用一定的内存和调度资源。如果一个系统同时创建成千上万个线程,就可能出现内存占用过高、上下文切换频繁、系统性能下降等问题。
比如一个 Web 服务中,如果每个请求都占用一个传统线程,当请求量非常大时,线程池很容易被打满。
ExecutorService executor = Executors.newFixedThreadPool(200);
这种方式虽然简单,但并发能力受到线程池大小限制。线程池太小,请求要排队;线程池太大,又会带来较高的系统开销。
二、Project Loom 是什么?
Project Loom 是 Java 平台的一个并发改进项目,它最重要的成果就是引入了:
虚拟线程 Virtual Thread
虚拟线程是一种由 JVM 管理的轻量级线程。它不像传统线程那样直接绑定一个操作系统线程,而是由 JVM 负责调度。
可以简单理解为:
传统线程:一个 Java 线程对应一个操作系统线程,成本较高
虚拟线程:大量 Java 虚拟线程复用少量操作系统线程,成本较低
虚拟线程的出现,让 Java 可以轻松创建大量并发任务,而不用像以前那样过度担心线程资源消耗。
三、虚拟线程解决了什么问题?
很多后端系统的瓶颈并不是 CPU,而是 IO 等待。
例如:
访问数据库
调用远程 REST API
读取文件
访问 Redis
上传下载 MinIO 文件
调用大模型接口
调用 OCR 服务
这些操作大部分时间都在“等结果”。传统线程在等待 IO 时,线程会被占住,不能去处理其他任务。
而虚拟线程在等待 IO 时,可以被 JVM 挂起,底层操作系统线程可以去执行其他虚拟线程。
这样一来,系统就可以用更低的成本支撑更多并发请求。
四、虚拟线程怎么使用?
从 Java 21 开始,虚拟线程已经正式可用。最简单的写法如下:
Thread.startVirtualThread(() -> {
System.out.println("Hello Virtual Thread");
});
如果要批量提交任务,可以使用虚拟线程执行器:
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
// 模拟一次远程调用
callRemoteService();
});
executor.submit(() -> {
// 模拟一次数据库查询
queryDatabase();
});
}
每一个任务都会使用一个虚拟线程执行。
这比传统固定线程池更适合大量 IO 型任务。
五、Spring Boot 中如何开启虚拟线程?
如果你使用的是 Java 21 + Spring Boot 3.2 及以上版本,可以在配置文件中开启虚拟线程:
spring:
threads:
virtual:
enabled: true
开启之后,Spring Boot 可以在部分场景下使用虚拟线程处理请求或执行任务。
例如,一个普通的 Controller 仍然可以用同步写法:
@RestController
@RequestMapping("/api")
public class DemoController {
@GetMapping("/hello")
public String hello() {
return callRemoteService();
}
private String callRemoteService() {
// 模拟远程接口调用
return "Hello Project Loom";
}
}
使用虚拟线程后,我们不一定要把代码改成复杂的异步回调,也可以继续保持同步代码的可读性。
六、Project Loom 和传统异步编程的区别
在 Project Loom 出现之前,Java 高并发场景常见方案包括:
线程池
CompletableFuture
响应式编程 Reactor / WebFlux
消息队列
这些方案都能解决一部分并发问题,但也会带来额外复杂度。
比如响应式编程虽然性能强,但代码往往会变成链式调用:
return userService.findUser(id)
.flatMap(user -> orderService.findOrders(user))
.map(result -> buildResponse(result));
这种方式对初学者来说不太直观,调试也相对复杂。
Project Loom 的优势是:
让开发者用接近传统同步代码的方式,获得更好的并发能力。
也就是说,你可以继续写:
User user = userService.findUser(id);
List<Order> orders = orderService.findOrders(user);
return buildResponse(user, orders);
代码更容易理解,维护成本也更低。
七、Project Loom 适合哪些场景?
Project Loom 特别适合 IO 密集型应用。
比如:
Web 后端服务
网关服务
RPC 服务
数据库查询较多的业务系统
微服务之间大量 REST API 调用
文件上传下载服务
Agent / OCR 任务调度系统
以 OCR 系统为例:
Java 后端接收任务
↓
调用 Python OCR 服务
↓
等待 OCR 结果
↓
访问 MinIO 获取文件
↓
写入 PostgreSQL
↓
推送任务状态给前端
这些操作大部分都是 IO 等待。使用虚拟线程后,可以让每个任务用一个虚拟线程执行,代码结构清晰,同时还能提升并发处理能力。
八、Project Loom 不适合哪些场景?
虚拟线程不是万能的。
如果任务是 CPU 密集型,比如:
大量图片压缩
复杂加密计算
视频转码
大规模矩阵计算
本地深度学习推理
这类任务主要消耗 CPU。CPU 核心数量是有限的,虚拟线程不能让 CPU 变多。
所以对于 CPU 密集型任务,仍然需要合理控制并发数量,避免把机器打满。
九、使用 Project Loom 要注意什么?
第一,不要误以为虚拟线程可以无限创建。虽然它很轻量,但任务背后的数据库连接、HTTP 连接、文件句柄等资源仍然是有限的。
第二,虚拟线程适合阻塞式 IO,但要注意第三方库是否兼容。如果某些库内部使用了特殊的阻塞方式,可能无法充分发挥虚拟线程优势。
第三,数据库连接池仍然要控制大小。即使你可以创建十万个虚拟线程,也不代表数据库能承受十万个连接。
第四,CPU 密集任务不要盲目使用虚拟线程,否则可能只是制造更多调度压力。
十、总结
Project Loom 是 Java 并发模型的一次重要升级。它通过虚拟线程降低了线程创建和调度的成本,让 Java 可以更自然地处理大量并发任务。
它最大的价值不是让代码变得更“炫技”,而是让我们可以继续使用简单、直观的同步编程模型,同时获得更强的并发能力。
一句话总结:
Project Loom 让 Java 在高并发 IO 场景下,可以用更简单的代码处理更多任务。
对于现代后端系统来说,尤其是微服务、任务调度、AI Agent、OCR 处理平台这类大量调用外部服务的系统,Project Loom 是非常值得学习和使用的技术。