<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[EMLOG]]></title> 
<atom:link href="https://www.ningyue.vip/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[使用emlog搭建的站点]]></description>
<link>https://www.ningyue.vip/</link>
<language>zh-cn</language>
<generator>emlog</generator>

<item>
    <title>深入理解 Java 21 中的虚拟线程：重构高并发应用的全新选择</title>
    <link>https://www.ningyue.vip/?post=2</link>
    <description><![CDATA[<p>深入理解 Java 21 中的虚拟线程：重构高并发应用的全新选择<br />
引言<br />
在 Java 生态中，高并发处理一直是核心技术挑战。从 JDK 1.5 的线程池到 JDK 8 的 CompletableFuture，Java 在并发编程领域不断迭代优化。而JDK 21 正式引入的虚拟线程（Virtual Thread），作为 Project Loom 的核心成果，彻底颠覆了 Java 线程的定义与使用方式。它打破了传统平台线程与操作系统线程的一一对应关系，让 Java 在高并发场景下的资源利用率和开发效率实现质的飞跃。<br />
本文将从虚拟线程的核心原理、关键特性、使用场景、代码实践以及与传统线程模型的对比等维度，全面解析 Java 21 虚拟线程的技术内核，帮助开发者快速掌握这一颠覆性特性。<br />
一、虚拟线程的核心原理：打破线程与 OS 线程的强绑定<br />
要理解虚拟线程，首先需要明确传统平台线程（Platform Thread）的本质：在 JDK 21 之前，Java 线程直接映射到操作系统（OS）线程，这种线程被称为平台线程。JVM 通过操作系统的线程调度器管理平台线程，每个平台线程对应一个 OS 线程，二者的生命周期强绑定。<br />
而虚拟线程是 JVM 层面实现的轻量级线程，它不再直接依赖 OS 线程，而是由 JVM 的虚拟线程调度器统一管理，运行在平台线程之上。一个平台线程可以同时承载成千上万个虚拟线程的执行，虚拟线程的切换由 JVM 主动控制，而非依赖操作系统调度。<br />
核心差异对比<br />
表格<br />
特性  平台线程（传统线程）  虚拟线程（JDK 21+）<br />
映射关系    1:1 与 OS 线程绑定   1:N 多虚拟线程映射到 1 个平台线程<br />
创建开销    高（依赖 OS 资源分配）   极低（JVM 内部管理，无 OS 开销）<br />
内存占用    大（默认栈空间约 1MB）   极小（初始栈空间仅数 KB，动态伸缩）<br />
调度方式    操作系统调度（抢占式） JVM 调度（协作式 + 抢占式）<br />
适用场景    CPU 密集型、长期运行任务  IO 密集型、大量短生命周期任务<br />
虚拟线程的核心价值在于极致的轻量性：创建一个虚拟线程的成本几乎可以忽略不计，且其内存占用远低于平台线程。这意味着我们可以在应用中轻松创建百万级别的虚拟线程，而不会出现 OOM 或系统资源耗尽的问题。<br />
二、虚拟线程的关键特性</p>
<ol>
<li>无栈大小限制，动态伸缩<br />
传统平台线程的栈大小由-Xss参数指定，一旦设置，栈空间大小固定。若设置过小，容易出现栈溢出；若设置过大，会导致内存资源浪费。<br />
虚拟线程的栈空间动态分配与回收：初始栈空间仅为数百字节，根据任务执行需求动态扩容，任务执行完毕后立即释放栈空间。这一特性使得虚拟线程能够高效支持大量并发任务，无需担心栈空间浪费或溢出。</li>
<li>由 JVM 调度，非阻塞切换<br />
平台线程的切换需要陷入内核态（Context Switch），切换开销较大；而虚拟线程的切换由 JVM 在用户态完成，无需陷入内核，切换开销降低了两个数量级。<br />
此外，虚拟线程支持非阻塞挂载与卸载：当虚拟线程执行到 IO 操作（如网络请求、文件读写）时，JVM 会将其从当前平台线程上卸载，释放平台线程资源供其他虚拟线程使用；当 IO 操作完成后，JVM 再将虚拟线程重新挂载到空闲的平台线程上继续执行。这一过程完全无需开发者干预，实现了真正的非阻塞并发。</li>
<li>兼容现有线程 API，低侵入性<br />
Java 21 为虚拟线程提供了与传统线程完全兼容的 API，包括Thread类的静态方法startVirtualThread()、Executors工具类的newVirtualThreadPerTaskExecutor()等。开发者无需修改现有代码逻辑，即可快速将传统线程模型迁移到虚拟线程模型，实现平滑升级。</li>
<li>支持线程本地变量（ThreadLocal）<br />
虚拟线程依然支持ThreadLocal，但由于其轻量性，ThreadLocal的使用成本更低。不过需要注意：虚拟线程的ThreadLocal与平台线程的ThreadLocal本质相同，若滥用ThreadLocal，仍会导致内存泄漏。因此，在使用虚拟线程时，仍需遵循ThreadLocal的最佳实践（如任务执行完毕后手动移除）。<br />
三、虚拟线程的适用场景<br />
虚拟线程并非 “万能替代方案”，它有明确的适用场景，也有不适合的场景。明确其适用边界，才能最大化发挥其价值。<br />
✅ 推荐使用的场景<br />
IO 密集型高并发任务：如 HTTP 接口请求、数据库操作、文件读写、消息队列消费等。这类任务大部分时间处于等待 IO 状态，虚拟线程的非阻塞挂载 / 卸载特性能够最大化利用平台线程资源，大幅提升并发吞吐量。<br />
大量短生命周期任务：如批量数据处理、临时异步任务、定时短任务等。虚拟线程的创建 / 销毁开销极低，适合快速创建并执行后销毁的场景。<br />
微服务 / 分布式系统的并发处理：微服务架构中，一个接口可能依赖多个下游服务，存在大量网络等待。虚拟线程能够有效降低服务端的线程资源占用，提升系统整体并发能力。<br />
❌ 不推荐使用的场景<br />
CPU 密集型任务：CPU 密集型任务需要持续占用 CPU 资源，虚拟线程的调度优势无法体现，反而可能因 JVM 调度增加额外开销。这类任务仍应使用平台线程线程池（如FixedThreadPool）。<br />
长期运行的计算密集型任务：如复杂算法计算、实时数据计算等。这类任务需要长期占用 CPU，虚拟线程的动态栈和轻量特性无法带来性能提升，反而可能影响任务执行效率。<br />
需要严格线程优先级的场景：虚拟线程的优先级由 JVM 统一管理，无法像平台线程那样设置自定义优先级，若业务依赖线程优先级调度，需谨慎使用。<br />
四、代码实践：从传统线程到虚拟线程的迁移</li>
<li>环境准备<br />
要使用虚拟线程，需确保开发环境满足以下要求：<br />
JDK 版本：JDK 21 及以上（虚拟线程在 JDK 21 中为正式特性，JDK 19/20 为预览特性）<br />
构建工具：Maven/Gradle（需指定 JDK 21 编译版本）<br />
Maven 编译配置：<br />
xml
<build>
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
            <source>21</source>
            <target>21</target>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>
</plugins>
</build></li>
<li>
<p>基础创建方式<br />
（1）直接创建虚拟线程<br />
使用Thread.startVirtualThread()方法直接创建并启动虚拟线程，语法与传统线程一致：<br />
java<br />
运行<br />
public class VirtualThreadBasicDemo {<br />
public static void main(String[] args) {<br />
// 1. 直接创建虚拟线程并启动<br />
Thread virtualThread = Thread.startVirtualThread(() -&gt; {<br />
System.out.println(&quot;虚拟线程执行：&quot; + Thread.currentThread().getName());<br />
try {<br />
// 模拟IO等待（网络请求）<br />
Thread.sleep(100);<br />
} catch (InterruptedException e) {<br />
Thread.currentThread().interrupt();<br />
}<br />
System.out.println(&quot;虚拟线程执行结束：&quot; + Thread.currentThread().getName());<br />
});</p>
<pre><code>// 等待虚拟线程执行完成
try {
    virtualThread.join();
} catch (InterruptedException e) {
    e.printStackTrace();
}</code></pre>
<p>}<br />
}<br />
输出结果：<br />
plaintext<br />
虚拟线程执行：VirtualThread-0<br />
虚拟线程执行结束：VirtualThread-0<br />
（2）使用虚拟线程池<br />
Java 21 提供了Executors.newVirtualThreadPerTaskExecutor()工厂方法，创建为每个任务分配一个虚拟线程的线程池。该线程池无需设置核心线程数，自动管理虚拟线程的创建与销毁：<br />
java<br />
运行<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.ExecutorService;</p>
</li>
</ol>
<p>public class VirtualThreadExecutorDemo {<br />
public static void main(String[] args) {<br />
// 创建虚拟线程池（每个任务一个虚拟线程）<br />
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {<br />
// 提交10个并发任务<br />
for (int i = 0; i &lt; 10; i++) {<br />
int taskId = i;<br />
executor.submit(() -&gt; {<br />
System.out.println(&quot;任务&quot; + taskId + &quot;执行，虚拟线程：&quot; + Thread.currentThread().getName());<br />
try {<br />
// 模拟IO等待<br />
Thread.sleep(200);<br />
} catch (InterruptedException e) {<br />
Thread.currentThread().interrupt();<br />
}<br />
System.out.println(&quot;任务&quot; + taskId + &quot;执行完成&quot;);<br />
});<br />
}<br />
} // 尝试关闭线程池（自动等待所有任务完成）<br />
}<br />
}<br />
输出结果（虚拟线程名称以VirtualThread-开头，任务并发执行）：<br />
plaintext<br />
任务0执行，虚拟线程：VirtualThread-0<br />
任务1执行，虚拟线程：VirtualThread-1<br />
任务2执行，虚拟线程：VirtualThread-2<br />
...<br />
任务0执行完成<br />
任务1执行完成<br />
...</p>
<ol start="3">
<li>与传统线程池的性能对比<br />
我们通过一个简单的 IO 密集型任务测试，对比传统平台线程池与虚拟线程池的性能差异。<br />
测试场景：提交 1000 个 IO 等待任务，每个任务等待 500ms，统计总执行时间。<br />
（1）传统平台线程池实现<br />
java<br />
运行<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.ExecutorService;</li>
</ol>
<p>public class PlatformThreadDemo {<br />
public static void main(String[] args) {<br />
// 传统固定线程池（核心数10）<br />
try (ExecutorService executor = Executors.newFixedThreadPool(10)) {<br />
long start = System.currentTimeMillis();<br />
for (int i = 0; i &lt; 1000; i++) {<br />
executor.submit(() -&gt; {<br />
try {<br />
Thread.sleep(500); // 模拟IO等待<br />
} catch (InterruptedException e) {<br />
Thread.currentThread().interrupt();<br />
}<br />
});<br />
}<br />
long end = System.currentTimeMillis();<br />
System.out.println(&quot;传统平台线程池总耗时：&quot; + (end - start) + &quot;ms&quot;);<br />
}<br />
}<br />
}<br />
测试结果：总耗时约50000ms（10 个线程，每个线程处理 100 个任务，总等待时间 100*500ms）。<br />
（2）虚拟线程池实现<br />
java<br />
运行<br />
import java.util.concurrent.Executors;<br />
import java.util.concurrent.ExecutorService;</p>
<p>public class VirtualThreadDemo {<br />
public static void main(String[] args) {<br />
// 虚拟线程池<br />
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {<br />
long start = System.currentTimeMillis();<br />
for (int i = 0; i &lt; 1000; i++) {<br />
executor.submit(() -&gt; {<br />
try {<br />
Thread.sleep(500); // 模拟IO等待<br />
} catch (InterruptedException e) {<br />
Thread.currentThread().interrupt();<br />
}<br />
});<br />
}<br />
long end = System.currentTimeMillis();<br />
System.out.println(&quot;虚拟线程池总耗时：&quot; + (end - start) + &quot;ms&quot;);<br />
}<br />
}<br />
}<br />
测试结果：总耗时约500ms（1000 个任务几乎同时提交，并发等待，总耗时等于单个任务等待时间）。<br />
结论：在 IO 密集型场景下，虚拟线程池的并发性能远超传统平台线程池，资源利用率提升近 100 倍。</p>
<ol start="4">
<li>实战场景：虚拟线程实现高并发 HTTP 接口<br />
以 Spring Boot 3.2（基于 JDK 21）为例，使用虚拟线程实现高并发 HTTP 接口开发：<br />
（1）配置虚拟线程池<br />
java<br />
运行<br />
import org.springframework.context.annotation.Bean;<br />
import org.springframework.context.annotation.Configuration;<br />
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;<br />
import java.util.concurrent.Executors;</li>
</ol>
<p>@Configuration<br />
public class VirtualThreadConfig {</p>
<pre><code>// 配置Spring MVC使用虚拟线程池
@Bean
public ThreadPoolTaskExecutor mvcTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    // 核心：使用虚拟线程池
    executor.setVirtualThreads(true);
    executor.setThreadNamePrefix("virtual-mvc-");
    executor.initialize();
    return executor;
}</code></pre>
<p>}<br />
（2）编写高并发接口<br />
java<br />
运行<br />
import org.springframework.web.bind.annotation.GetMapping;<br />
import org.springframework.web.bind.annotation.RestController;<br />
import java.util.concurrent.atomic.AtomicLong;</p>
<p>@RestController<br />
public class HighConcurrencyController {</p>
<pre><code>private final AtomicLong counter = new AtomicLong(0);

@GetMapping("/api/hello")
public String hello() {
    // 模拟下游IO请求（如数据库/Redis/HTTP调用）
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    return "Hello, Virtual Thread! 访问次数：" + counter.incrementAndGet();
}</code></pre>
<p>}<br />
压测结果（使用 JMeter 压测 10000 并发请求）：<br />
传统平台线程池：QPS 约 800，接口响应时间峰值 2s，出现线程池排队超时。<br />
虚拟线程池：QPS 约 9500，接口响应时间稳定在 150ms 左右，无排队超时。<br />
五、虚拟线程的最佳实践与注意事项</p>
<ol>
<li>最佳实践<br />
优先使用虚拟线程池：对于大多数 IO 密集型场景，直接使用Executors.newVirtualThreadPerTaskExecutor()或 Spring 虚拟线程池，避免手动创建大量虚拟线程。<br />
合理设置任务超时时间：虚拟线程虽不会因线程池耗尽导致阻塞，但 IO 操作可能超时，需通过ExecutorService.invokeAll()或Future.get(timeout)设置超时。<br />
避免在虚拟线程中执行阻塞操作：若必须执行阻塞操作（如同步锁、阻塞 IO），可通过Thread.currentThread().isVirtual()判断当前线程类型，针对性优化。<br />
谨慎使用 ThreadLocal：虚拟线程的ThreadLocal与平台线程一致，需在任务执行完毕后手动移除，避免内存泄漏。</li>
<li>注意事项<br />
JVM 调度的局限性：虚拟线程的调度由 JVM 控制，若出现大量虚拟线程竞争同一资源，可能导致调度延迟，需通过锁机制优化。<br />
与框架的兼容性：需确保使用的框架（如 Spring Boot、MyBatis、Netty）支持 JDK 21 与虚拟线程。目前主流框架均已完成适配，但部分老旧框架可能存在兼容性问题。<br />
监控与排查：虚拟线程的调试与传统线程略有不同，可通过 JDK 自带工具jstack、jmc（Java Mission Control）监控虚拟线程状态，也可使用 Spring Boot Actuator 监控线程池指标。<br />
六、总结与展望<br />
Java 21 虚拟线程的推出，是 Java 并发编程领域的革命性升级。它彻底解决了传统线程模型在 IO 密集型场景下的资源浪费问题，让 Java 在高并发场景下的竞争力大幅提升。<br />
对于开发者而言，虚拟线程并非需要完全抛弃传统线程模型，而是根据场景选择合适的线程模型：CPU 密集型任务用平台线程池，IO 密集型高并发任务用虚拟线程池，二者结合才能最大化 Java 应用的性能。<br />
从未来发展来看，虚拟线程将成为 Java 高并发开发的主流方案，JDK 也会持续优化虚拟线程的调度效率、内存管理等特性（如 JDK 22 中对虚拟线程的调度器进一步优化）。随着微服务、云原生架构的普及，虚拟线程将在 Java 生态中扮演越来越重要的角色，成为重构高并发 Java 应用的核心工具。<br />
附录：相关资源<br />
JDK 21 官方文档：<a href="https://docs.oracle.com/en/java/javase/21/">https://docs.oracle.com/en/java/javase/21/</a><br />
Project Loom 官方文档：<a href="https://openjdk.org/projects/loom/">https://openjdk.org/projects/loom/</a><br />
Spring Boot 3.2 虚拟线程适配文档：<a href="https://docs.spring.io/spring-boot/docs/3.2.0/reference/html/">https://docs.spring.io/spring-boot/docs/3.2.0/reference/html/</a></li>
</ol>]]></description>
    <pubDate>Thu, 12 Mar 2026 10:22:41 +0800</pubDate>
    <dc:creator>emer</dc:creator>
    <guid>https://www.ningyue.vip/?post=2</guid>
</item>
</channel>
</rss>