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

Java小白-线程 vs 虚拟线程,Java并发的新旧对决

一、什么是传统线程?

        Java 里的传统线程(java.lang.Thread)其实是 操作系统级别的线程(OS Thread),每创建一个 Thread 对象,JVM 底层会向操作系统申请内核线程资源。特点有:线程上下文切换成本高;需要配合线程池(如 ThreadPoolExecutor)来复用;IO 阻塞会卡死一个真实线程。

二、什么是虚拟线程(Virtual Thread)?

        虚拟线程(Java 21 正式引入,源自 Project Loom),是由 JVM 自己调度的轻量线程,不再直接绑定一个 OS 线程。而它的特点是:由 JVM 的调度器托管,切换更轻;可以创建海量线程(百万级别);IO 阻塞自动挂起,节省内核线程。

三、传统线程 VS 虚拟线程 —— 实现对比

下面是一个示例,用来演示如何启动 1 万个线程 / 虚拟线程,分别跑一个简单的任务。

传统线程:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TraditionalThreadDemo {public static void main(String[] args) throws InterruptedException {// 创建一个固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(10);long start = System.currentTimeMillis();// 启动 100 个任务for (int i = 0; i < 100; i++) {int taskId = i;executor.submit(() -> {System.out.println("传统线程执行任务:" + taskId + " - " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟 IO} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();while (!executor.isTerminated()) {Thread.sleep(100);}long end = System.currentTimeMillis();System.out.println("传统线程总耗时:" + (end - start) + " ms");}
}

虚拟线程--需要 JDK 21+:

public class VirtualThreadDemo {public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();// 启动 100 个虚拟线程for (int i = 0; i < 100; i++) {int taskId = i;Thread.startVirtualThread(() -> {System.out.println("虚拟线程执行任务:" + taskId + " - " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟 IO} catch (InterruptedException e) {e.printStackTrace();}});}// 主线程等待足够时间,确保所有虚拟线程完成Thread.sleep(2000);long end = System.currentTimeMillis();System.out.println("虚拟线程总耗时:" + (end - start) + " ms");}
}

对比结果:

特性传统线程虚拟线程
创建成本超低
数量1 万就容易撑爆百万没问题
调度OS 调度JVM 自己调度
IO 阻塞阻塞 OS 线程自动挂起,释放内核线程
适用场景CPU 密集型 / 大任务IO 密集型 / 高并发服务

还可以把任务量调到 100000,传统线程会直接卡死或 OOM,但虚拟线程能稳稳跑。另外可以把 Thread.sleep(1000) 换成 HTTP 请求,能更真实地体现 IO 阻塞优势。

http://www.lryc.cn/news/587006.html

相关文章:

  • 垃圾收集器-Serial Old
  • 教程:如何查看浏览器扩展程序的源码
  • 【操作系统-Day 5】通往内核的唯一桥梁:系统调用 (System Call)
  • 飞算 JavaAI 智能编程助手:颠覆编程旧模式,重构开发生态
  • 【Linux | 网络】应用层
  • 算法学习笔记:19.牛顿迭代法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 在 Spring Boot 中使用 MyBatis 的 XML 文件编写 SQL 语句详解
  • 飞算JavaAI:开启 Java 开发 “人机协作” 新纪元
  • [Linux入门 ] RAID存储技术概述
  • [Dify]-基础入门6-Dify 的工作流 (Workflow) 详解(入门篇)
  • [Rust 基础课程]Hello World
  • Linux进程状态实战指南:转换关系、监控命令与状态解析
  • 二叉树算法详解和C++代码示例
  • Docker 快速上手
  • 深入理解 Linux 文件系统层级结构
  • 【Docker基础】Dockerfile指令速览:文件与目录操作指令详解
  • 【论文阅读】AdaptThink: Reasoning Models Can Learn When to Think
  • 系统思考:系统性抛弃
  • 深入解析Hadoop RPC:技术细节与推广应用
  • 【C++】优先队列简介与模拟实现 + 仿函数
  • 谷歌在软件工程领域应用AI的进展与未来展望
  • day5--上传视频
  • h() 函数
  • 现代Web开发实践:从零到全栈的高效率攻略
  • JAVA 反射总结
  • 从零开始跑通3DGS教程:(五)3DGS训练
  • lambdastream深入剖析
  • Dubbo-Admin 安装与使用指南:可视化管理 Dubbo 服务
  • uView UI 组件大全
  • MySQL优化高手笔记