当前位置: 首页 > news >正文

Java 21 虚拟线程 vs 缓存线程池与固定线程池

探索 Java 并发如何从 Java 8 的增强发展到 Java 21 的虚拟线程,从而实现轻量级、可扩展且高效的多线程处理。

引言

并发编程仍然是构建可扩展、响应式 Java 应用程序的关键部分。多年来,Java 持续增强了其多线程编程能力。本文回顾了从 Java 8 到 Java 21 并发的演进,重点介绍了重要的改进以及 Java 21 中引入的具有重大影响的虚拟线程。

从 Java 8 开始,并发 API 出现了显著的增强,例如原子变量、并发映射以及集成 lambda 表达式以实现更具表现力的并行编程。

Java 8 引入的关键改进包括:

  • 线程与执行器
  • 同步与锁
  • 原子变量与 ConcurrentMap

Java 21 于 2023 年底发布,带来了虚拟线程这一重大演进,从根本上改变了 Java 应用程序处理大量并发任务的方式。虚拟线程为服务器应用程序提供了更高的可扩展性,同时保持了熟悉的"每个请求一个线程"的编程模型。

或许,Java 21 中最重要的特性就是虚拟线程。
在 Java 21 中,Java 的基本并发模型保持不变,Stream API 仍然是并行处理大型数据集的首选方式。
随着虚拟线程的引入,并发 API 现在能提供更好的性能。在当今的微服务和可扩展服务器应用领域,线程数量必须增长以满足需求。虚拟线程的主要目标是使服务器应用程序能够实现高可扩展性,同时仍使用简单的"每个请求一个线程"模型。

虚拟线程

在 Java 21 之前,JDK 的线程实现使用的是操作系统线程的薄包装器。然而,操作系统线程代价高昂:

  • 如果每个请求在其整个持续时间内消耗一个操作系统线程,线程数量很快就会成为可扩展性的瓶颈。
  • 即使使用线程池,吞吐量仍然受到限制,因为实际线程数量是有上限的。

虚拟线程的目标是打破 Java 线程与操作系统线程之间的 1:1 关系。
虚拟线程应用了类似于虚拟内存的概念。正如虚拟内存将大的地址空间映射到较小的物理内存一样,虚拟线程允许运行时通过将它们映射到少量操作系统线程来制造拥有许多线程的假象。

平台线程是操作系统线程的薄包装器。
而虚拟线程并不绑定到任何特定的操作系统线程。虚拟线程可以执行平台线程可以运行的任何代码。这是一个主要优势——现有的 Java 代码通常无需修改或仅需少量修改即可在虚拟线程上运行。虚拟线程由平台线程承载,这些平台线程仍然由操作系统调度。

例如,您可以像这样创建一个使用虚拟线程的执行器:

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

对比示例

虚拟线程仅在主动执行 CPU 密集型任务时才消耗操作系统线程。虚拟线程在其生命周期内可以在不同的载体线程上挂载或卸载。

通常,当虚拟线程遇到阻塞操作时,它会自行卸载。一旦该阻塞任务完成,虚拟线程通过挂载到任何可用的载体线程上来恢复执行。这种挂载和卸载过程频繁且透明地发生——不会阻塞操作系统线程。

示例 — 源代码

Example01CachedThreadPool.java

在此示例中,使用缓存线程池创建了一个执行器:

var executor = Executors.newCachedThreadPool()
package threads;import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/public class Example01CachedThreadPool {public void executeTasks(final int NUMBER_OF_TASKS) {final int BLOCKING_CALL = 1;System.out.println("Number of tasks which executed using 'newCachedThreadPool()' " + NUMBER_OF_TASKS + " tasks each.");long startTime = System.currentTimeMillis();try (var executor = Executors.newCachedThreadPool()) {IntStream.range(0, NUMBER_OF_TASKS).forEach(i -> {executor.submit(() -> {// 模拟阻塞调用Thread.sleep(Duration.ofSeconds(BLOCKING_CALL));return i;});});} catch (Exception e) {throw new RuntimeException(e);}long endTime = System.currentTimeMillis();System.out.println("For executing " + NUMBER_OF_TASKS + " tasks duration is: " + (endTime - startTime) + " ms");}}
package threads;import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Example01CachedThreadPoolTest {@Test@Order(1)public void test_1000_tasks() {Example01CachedThreadPool example01CachedThreadPool = new Example01CachedThreadPool();example01CachedThreadPool.executeTasks(1000);}@Test@Order(2)public void test_10_000_tasks() {Example01CachedThreadPool example01CachedThreadPool = new Example01CachedThreadPool();example01CachedThreadPool.executeTasks(10_000);}@Test@Order(3)public void test_100_000_tasks() {Example01CachedThreadPool example01CachedThreadPool = new Example01CachedThreadPool();example01CachedThreadPool.executeTasks(100_000);}@Test@Order(4)public void test_1_000_000_tasks() {Example01CachedThreadPool example01CachedThreadPool = new Example01CachedThreadPool();example01CachedThreadPool.executeTasks(1_000_000);}}

我 PC 上的测试结果:

Example02FixedThreadPool.java

使用固定线程池创建执行器:

var executor = Executors.newFixedThreadPool(500)
package threads;import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/public class Example02FixedThreadPool {public void executeTasks(final int NUMBER_OF_TASKS) {final int BLOCKING_CALL = 1;System.out.println("Number of tasks which executed using 'newFixedThreadPool(500)' " + NUMBER_OF_TASKS + " tasks each.");long startTime = System.currentTimeMillis();try (var executor = Executors.newFixedThreadPool(500)) {IntStream.range(0, NUMBER_OF_TASKS).forEach(i -> {executor.submit(() -> {// 模拟阻塞调用Thread.sleep(Duration.ofSeconds(BLOCKING_CALL));return i;});});}   catch (Exception e) {throw new RuntimeException(e);}long endTime = System.currentTimeMillis();System.out.println("For executing " + NUMBER_OF_TASKS + " tasks duration is: " + (endTime - startTime) + " ms");}}
package threads;import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Example02FixedThreadPoolTest {@Test@Order(1)public void test_1000_tasks() {Example02FixedThreadPool example02FixedThreadPool = new Example02FixedThreadPool();example02FixedThreadPool.executeTasks(1000);}@Test@Order(2)public void test_10_000_tasks() {Example02FixedThreadPool example02FixedThreadPool = new Example02FixedThreadPool();example02FixedThreadPool.executeTasks(10_000);}@Test@Order(3)public void test_100_000_tasks() {Example02FixedThreadPool example02FixedThreadPool = new Example02FixedThreadPool();example02FixedThreadPool.executeTasks(100_000);}@Test@Order(4)public void test_1_000_000_tasks() {Example02FixedThreadPool example02FixedThreadPool = new Example02FixedThreadPool();example02FixedThreadPool.executeTasks(1_000_000);}}

我 PC 上的测试结果:

Example03VirtualThread.java

使用虚拟线程每任务执行器创建执行器:

var executor = Executors.newVirtualThreadPerTaskExecutor()
package threads;import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/public class Example03VirtualThread {public void executeTasks(final int NUMBER_OF_TASKS) {final int BLOCKING_CALL = 1;System.out.println("Number of tasks which executed using 'newVirtualThreadPerTaskExecutor()' " + NUMBER_OF_TASKS + " tasks each.");long startTime = System.currentTimeMillis();try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {IntStream.range(0, NUMBER_OF_TASKS).forEach(i -> {executor.submit(() -> {// 模拟阻塞调用Thread.sleep(Duration.ofSeconds(BLOCKING_CALL));return i;});});}   catch (Exception e) {throw new RuntimeException(e);}long endTime = System.currentTimeMillis();System.out.println("For executing " + NUMBER_OF_TASKS + " tasks duration is: " + (endTime - startTime) + " ms");}}
package threads;import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;/**** @author Milan Karajovic <milan.karajovic.rs@gmail.com>**/@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Example03VirtualThreadTest {@Test@Order(1)public void test_1000_tasks() {Example03VirtualThread example03VirtualThread = new Example03VirtualThread();example03VirtualThread.executeTasks(1000);}@Test@Order(2)public void test_10_000_tasks() {Example03VirtualThread example03VirtualThread = new Example03VirtualThread();example03VirtualThread.executeTasks(10_000);}@Test@Order(3)public void test_100_000_tasks() {Example03VirtualThread example03VirtualThread = new Example03VirtualThread();example03VirtualThread.executeTasks(100_000);}@Test@Order(4)public void test_1_000_000_tasks() {Example03VirtualThread example03VirtualThread = new Example03VirtualThread();example03VirtualThread.executeTasks(1_000_000);}@Test@Order(5)public void test_2_000_000_tasks() {Example03VirtualThread example03VirtualThread = new Example03VirtualThread();example03VirtualThread.executeTasks(2_000_000);}}

我 PC 上的测试结果:

结论

您可以清楚地看到用于处理所有 NUMBER_OF_TASKS 的不同执行器实现之间的执行时间差异。值得尝试不同的 NUMBER_OF_TASKS 值以观察性能变化。

虚拟线程的优势在处理大量任务时变得尤其明显。当 NUMBER_OF_TASKS 设置为较高的数值时——例如 1,000,000——性能差距是显著的。如下表所示,虚拟线程在处理大量任务时效率要高得多:

我确信,在澄清这一点之后,如果您的应用程序使用并发 API 处理大量任务,您会认真考虑迁移到 Java 21 并利用虚拟线程。在许多情况下,这种转变可以显著提高应用程序的性能和可扩展性。

源代码:GitHub Repository – Comparing Threads in Java 21


【注】本文译自:Java 21 Virtual Threads vs Cached and Fixed Threads

http://www.jsqmd.com/news/26466/

相关文章:

  • 2025年知名的盾构施工煤矿道岔厂家实力及用户口碑排行榜
  • 揭秘Deepseek:只用GPT-4成本的6%,却做出更聪明的AI?
  • 2025年口碑好的暗扣隐藏式家具拉手厂家实力及用户口碑排行榜
  • Modern newspapers
  • 2025新一代公众号编辑器,有一云AI以绝对优势拔得头筹
  • 2025年二手航吊吨袋厂家推荐及选购参考榜
  • C++项目指定依赖路径
  • 2025 年 10 月气缸管厂家推荐排行榜,精密气缸管,不锈钢气缸管,珩磨气缸管,薄壁气缸管,焊接气缸管,冷拔气缸管,食品级气缸管,海洋用气缸管公司推荐
  • 2025年评价高的格栅机维修厂家推荐及采购参考
  • 2025年口碑好的中温伴热带厂家最新用户好评榜
  • 2025年10月卖得好的学习机品牌推荐:销量榜排行与可信评测
  • 2025 年 10 月三层绝缘线厂家推荐排行榜,东特/大亚/TOTOKU/古河/TIW-2/TIW-3/TIW-4/TIW-E/TIW-2S/TEX-E 三层绝缘线公司推荐
  • 2025年10月卖得好的学习机品牌推荐:销量榜对比指南
  • [题解]G. Puzzle II - The 3rd Universal Cup. Stage 2: Zielona Gra
  • 2025年10月精华液推荐榜:淡斑提亮多效精华权威排名发布
  • 2025年10月教育资源好的学习机品牌推荐:家长关注榜对比与实测排行
  • 2025年10月教育资源好的学习机品牌推荐:热门榜数据化评价
  • 2025年10月性价比高的学习机品牌推荐:市场销量榜解析高价值学习方案
  • 2025年读书郎深度解析:26年教育科技长跑的硬实力与隐忧,
  • 2025年读书郎深度解析:26年教育科技长跑的硬实力与隐忧。
  • 2025 年 10 月中央空调厂家推荐排行榜,美的/海信/大金/格力/约克/海尔,商用中央空调,家用中央空调,工业中央空调安装维修服务优质品牌精选
  • 2025年10月精华液排行榜:多肤质适配的精选清单
  • 2025 年 10 月砂磨机厂家推荐排行榜,立式砂磨机,立式纳米砂磨机,小型立式砂磨机公司推荐,高效研磨与稳定性能深度解析
  • 2025年10月郑州遗产继承律师对比榜:真实口碑与案例全解析
  • 2025年10月黄褐斑改善产品推荐榜:五款明星单品多维度对比排行
  • 2025年热门的叉车高压直流继电器厂家最新推荐排行榜
  • 2025年10月郑州遗产继承律师选择榜:五强机构公开数据对比与排行
  • 2025年比较好的不锈钢保温杯优质厂家推荐榜单
  • 2025 年 10 月气动执行器厂家推荐排行榜,齿轮齿条执行器,拨叉式执行器,角行程执行器,不锈钢执行器,三段式执行器,快速执行器,执行器附件,气动执行器附件公司推荐
  • 2025年评价高的汤锅不粘锅最新TOP厂家排名