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 阻塞优势。