【Java】虚拟线程详解

前言

虚拟线程在JDK19得时候已经推出,在预览模式中即可使用,在JDK21中虚拟线程正式成为标准特性,今天就主要介绍一下虚拟线程的使用方法。

一、虚拟线程介绍

虚拟线程是轻量级的线程,与平台线程不同的是虚拟线程由 JVM 管理而不是操作系统直接管理,这使得创建数百万个虚拟线程成为可能,而不会产生传统平台线程的开销,虚拟线程实际上运行在平台线程上,多个虚拟线程可以共享同一个平台线程,虚拟线程的概念和python的携程是同一类概念。虚拟线程利用了 Java 的 Fork-Join 框架来调度和管理,Fork-Join 框架提供了一个工作窃取(work-stealing)算法,可以高效地在不同的载体线程之间分配任务,JVM 内部使用 FIFO 队列来维护就绪状态的虚拟线程。

主要优势

优势 说明
高吞吐量 虚拟线程非常轻量,可以轻松创建大量线程来处理并发任务
降低资源消耗 相比于平台线程,虚拟线程占用的内存更少,上下文切换开销更小
简化并发编程 可以使用简单的阻塞式 I/O 操作,而不用担心阻塞宝贵的平台线程
更好的伸缩性 应用程序可以更好地扩展以处理大量并发连接

二、虚拟线程应用场景

虚拟线程适用于I/O密集型任和阻塞式任务。虚拟线程的主要设计目标是处理大量I/O密集型任务,如网络请求、数据库访问等;虚拟线程有透明的挂起和恢复机制,当虚拟线程执行阻塞操作时,JVM会自动将其从平台线程上解绑,让平台线程可以执行其他任务

虚拟线程适用于阻塞式任务
注意:

避免用于 CPU 密集型任务:对于计算密集型任务,传统的平台线程可能更合适

结合 CompletableFuture 使用:可以与 CompletableFuture 结合使用,构建复杂的异步处理流程

三、虚拟线程创建方式和用法

(一)使用Thread.ofVirtual()创建

java 复制代码
Thread virtualThread = Thread.ofVirtual()
                .name("虚拟线程")
                .start(() -> {
                    System.out.println("下次呢行名: " + Thread.currentThread());
                });

(二)使用Thread.startVirtualThread()创建

java 复制代码
 Thread.startVirtualThread(() -> {
            System.out.println("执行");
        });

(三)使用Executors创建(推荐使用此方式来构建)

java 复制代码
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            Future<String> future = executor.submit(() -> {
                Thread.sleep(1000); // 不会阻塞平台线程
                return "结果";
            });
            try {
                //获取结果
                System.out.println(future.get());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            }
        }

注意: 为什么推荐使用使用Executors创建虚拟线程?

ExecutorService 提供了统一的任务调度机制,能够自动管理虚拟线程的生命周期,避免手动创建和销毁线程带来的复杂性。

通过 Executors.newVirtualThreadPerTaskExecutor() 创建的虚拟线程池,会在任务完成后自动回收资源,减少内存泄漏风险。

四、案例Demo

java 复制代码
public static void main(String[] args) {
        //使用Executors构建百万虚拟线程
        long startTime = System.currentTimeMillis();
        //使用CountDownLatch统一返回结果
        CountDownLatch latch = new CountDownLatch(1000000);
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 1000000; i++){
                executor.submit(() -> {
                    try {
                        Thread.sleep(1000); //模拟任务执行1s
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    latch.countDown(); // 每个任务完成后计数减一
                });

            }
            try {
                latch.await(); // 等待所有任务完成
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            long endTime = System.currentTimeMillis();
            System.out.println("创建并执行一百万个虚拟线程耗时: " + (endTime - startTime) + " ms");
        }
    }

执行结果:

可见,百万级任务执行只需要大概19s,相对于平台线程来说,极大提高了效率。

为了帮助更多像你一样的读者,我将持续在专栏中分享技术干货和实用技巧。如果你觉得这篇文章对你有帮助,可以考虑关注我的专栏,谢谢。

相关推荐
霍理迪1 小时前
JS—事件高级
开发语言·javascript·ecmascript
逍遥德1 小时前
Maven教程.02-基础-pom.xml 使用标签大全
java·后端·maven·软件构建
范特西.i1 小时前
QT聊天项目(8)
开发语言·qt
烟花落o2 小时前
栈和队列的知识点及代码
开发语言·数据结构·笔记·栈和队列·编程学习
crescent_悦2 小时前
C++:Have Fun with Numbers
开发语言·c++
mjhcsp2 小时前
C++轮廓线 DP:从原理到实战的深度解析
开发语言·c++·动态规划
甲枫叶2 小时前
【claude热点资讯】Claude Code 更新:手机遥控电脑开发,Remote Control 功能上线
java·人工智能·智能手机·产品经理·ai编程
额,不知道写啥。2 小时前
P5354 [Ynoi Easy Round 2017] 由乃的 OJ
java·开发语言·算法
代码无bug抓狂人2 小时前
C语言之单词方阵——深搜(很好的深搜例题)
c语言·开发语言·算法·深度优先