java虚拟线程的超详细讲解

 更新时间:2025年10月11日 09:37:43   作者:画船听雨眠aa  
虚拟线程是由Java运行时而不是操作系统实现的Java线程,和传统线程(或称之为平台线程)之间的主要区别在于,我们可以很容易地在同一个Java进程中运行大量活动的虚拟线程,甚至数百万个,这篇文章主要介绍了java虚拟线程的相关资料,需要的朋友可以参考下

前言

在 Java 并发编程的历史中,线程模型的演进一直是性能优化的核心。从最初的平台线程到如今的虚拟线程,Java 正在经历一场并发编程的范式转变。

一、传统线程(平台线程):

1.1什么是平台线程

平台线程是 Java 诞生以来就存在的线程模型,它与操作系统内核线程是一对一(1:1)映射的关系:每创建一个 Java 线程,操作系统就会对应创建一个内核线程,线程的调度完全由操作系统负责。

这种模型的本质是 "将 Java 线程直接委托给操作系统管理",优点是实现简单,能直接利用操作系统的线程调度能力,但缺点也同样显著。

1.2 平台线程的核心痛点

(1)资源消耗巨大

每个平台线程都需要独立的栈空间(默认 1MB 以上)和内核资源,这导致一个进程能创建的线程数量非常有限。在常规服务器上,最多只能创建几千个平台线程,超过这个数量就会出现 OOM(内存溢出)或系统崩溃。

(2)调度成本高昂

操作系统调度线程时需要在用户态和内核态之间切换(上下文切换),每次切换耗时约 1-10 微秒。在高并发场景下,大量线程的频繁切换会严重消耗 CPU 资源,导致 "线程调度 overhead 超过实际任务执行时间" 的尴尬局面。

(3)并发编程门槛高

为了规避资源限制,开发者必须使用线程池手动控制线程数量,但线程池参数(核心线程数、最大线程数、队列大小)的调优极其复杂,稍有不慎就会出现 "线程耗尽" 或 "资源浪费" 的问题。

二、虚拟线程:

面对平台线程的局限性,Java 19(2022 年 9 月)正式引入虚拟线程(Virtual Threads),并在 Java 21 中成为稳定特性。它不是对平台线程的修补,而是一种全新的线程模型。

2.1什么是虚拟线程

虚拟线程是由 JVM 管理的用户态线程,它不直接映射到操作系统内核线程,而是通过 "多对多(M:N)" 的方式映射到少量平台线程上:多个虚拟线程可以共享一个平台线程,由 JVM 负责在用户态完成调度。

简单说,虚拟线程就像是 "JVM 级别的轻量级线程",它的创建、销毁和调度完全由 JVM 控制,无需操作系统介入。

2.2虚拟线程的核心优势

(1)极致轻量化

  • 初始栈大小仅几百字节(平台线程是 MB 级)
  • 支持创建百万级甚至千万级线程(平台线程仅支持几千级)
  • 线程创建成本降低 99% 以上

(2)智能调度机制

        当虚拟线程执行阻塞操作(如网络 IO、文件读写)时,JVM 会自动将其 "挂起",并将底层平台线程让给其他虚拟线程使用。这种 "阻塞即让出" 的特性,彻底解决了传统线程 "阻塞时浪费资源" 的问题。

(3)兼容现有代码

虚拟线程完全兼容Thread、Runnable、ExecutorService等现有并发 API,无需学习新框架就能上手,这意味着你可以用同步代码的写法,实现异步代码的性能。

对比

特性

平台线程(普通线程)

虚拟线程(Virtual Threads)

底层映射关系

1:1(Java 线程→操作系统线程)

M:N(多个虚拟线程→少量操作系统线程)

资源占用

高(栈内存固定 1MB+)

低(栈内存动态分配,初始仅几百字节)

最大并发支持

几千个线程

百万级线程

调度方

操作系统内核(内核态调度)

JVM(用户态调度)

上下文切换成本

高(约 1-10 微秒,需内核态切换)

低(约 0.1 微秒,用户态内完成)

阻塞时资源利用率

低(线程阻塞时仍占用操作系统线程)

高(阻塞时自动释放底层线程资源)

适用场景

计算密集型任务

IO 密集型任务(网络、数据库、文件 IO)

创建成本

高(需操作系统调用)

极低(JVM 直接创建)

代码测试

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadComparisonDemo {
    private static final int TASK_COUNT = 10000; // 任务数量
    private static final int IO_DELAY = 10;      // 模拟IO延迟(毫秒)

    public static void main(String[] args) throws InterruptedException {
        System.out.println("任务数量: " + TASK_COUNT + ", IO延迟: " + IO_DELAY + "ms");

        // 测试普通线程
        long platformTime = measureTime(() -> runWithPlatformThreads());
        System.out.printf("普通线程耗时: %d ms%n", platformTime);

        // 测试虚拟线程
        long virtualTime = measureTime(() -> runWithVirtualThreads());
        System.out.printf("虚拟线程耗时: %d ms%n", virtualTime);

        // 计算性能提升百分比
        double improvement = (1.0 - (double) virtualTime / platformTime) * 100;
        System.out.printf("虚拟线程性能提升: %.2f%%%n", improvement);
    }

    // 普通线程测试
    private static void runWithPlatformThreads() throws InterruptedException {
        try (ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) {
            for (int i = 0; i < TASK_COUNT; i++) {
                executor.submit(() -> simulateIoTask());
            }
        }
    }

    // 虚拟线程测试
    private static void runWithVirtualThreads() throws InterruptedException {
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < TASK_COUNT; i++) {
                executor.submit(() -> simulateIoTask());
            }
        }
    }

    // 模拟IO密集型任务
    private static void simulateIoTask() {
        try {
            Thread.sleep(IO_DELAY); // 模拟IO等待时间
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 计时辅助方法
    private static long measureTime(Runnable action) {
        Instant start = Instant.now();
        try {
            action.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Duration.between(start, Instant.now()).toMillis();
    }
}    

总结

到此这篇关于java虚拟线程的文章就介绍到这了,更多相关java虚拟线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot neo4j的配置代码

    springboot neo4j的配置代码

    小编最近的工作中遇到了一些知识图谱的工作,自然就用到了图数据库,这一NoSQL 数据库可以很好的展示节点之间的关联关系,对于一些图谱的关系操作是很好的选择,下面来介绍下 Springboot 配置Neo4J的问题
    2021-12-12
  • springboot+vue部署按照及运行方法

    springboot+vue部署按照及运行方法

    在本篇文章里小编给大家整理了关于springboot+vue部署按照及运行方法和实例内容,需要的朋友们学习参考下。
    2020-01-01
  • 超个性修改SpringBoot项目的启动banner的方法

    超个性修改SpringBoot项目的启动banner的方法

    这篇文章主要介绍了超个性修改SpringBoot项目的启动banner的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • java 代码块与静态代码块加载顺序

    java 代码块与静态代码块加载顺序

    这篇文章主要介绍了java 代码块与静态代码块加载顺序的相关资料,需要的朋友可以参考下
    2017-07-07
  • Java基础:流Stream详解

    Java基础:流Stream详解

    Stream流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。这篇文章主要介绍了Java8新特性Stream流的相关资料,需要的朋友参考下吧
    2021-09-09
  • JVM垃圾回收机制和垃圾回收器详细解说

    JVM垃圾回收机制和垃圾回收器详细解说

    这篇文章主要介绍了JVM垃圾回收机制和垃圾回收器,为了让程序员更加专注于代码的实现,而不用过多的考虑内存释放的问题,所以在Java语言中,有了自动的垃圾回收机制,也是我们常常提及的GC,需要的朋友可以参考下
    2022-07-07
  • java实现的AES秘钥生成算法示例

    java实现的AES秘钥生成算法示例

    这篇文章主要介绍了java实现的AES秘钥生成算法,结合实例形式分析了AES秘钥生成算法原理与实现技巧,需要的朋友可以参考下
    2017-01-01
  • 搭建MyBatis-Plus框架并进行数据库增删改查功能

    搭建MyBatis-Plus框架并进行数据库增删改查功能

    这篇文章主要介绍了搭建MyBatis-Plus框架并进行数据库增删改查,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • JAVA Log 日志级别和使用配置示例

    JAVA Log 日志级别和使用配置示例

    本文介绍了Java中主流的日志框架,包括Logback和Log4j2,并详细解释了日志级别及其使用场景,同时,还提供了配置示例和使用技巧,如正确的日志记录方式、异常日志记录、性能优化以及环境特定的日志配置,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2025-11-11
  • Caused by: java.lang.NumberFormatException: For input string: “port“(问题解决)

    Caused by: java.lang.NumberFormatException: For input s

    这篇文章主要介绍了Caused by: java.lang.NumberFormatException: For input string: “port“,本文给大家分享完美解决方法,需要的朋友可以参考下
    2023-01-01

最新评论