平台线程与虚拟线程
了解各自适用的场景
平台线程与虚拟线程 是 CoddyKit 上的免费 Java Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
两类线程
Java 现在有两种线程类型。平台线程是围绕 OS 线程的经典封装。虚拟线程轻量且由 JVM 管理。
掌握何时选择哪一种,是编写可扩展并发 Java 程序的核心。
创建平台线程
您可以使用 Thread.ofPlatform() 创建平台线程,它对应于 Thread.ofVirtual()。
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread p = Thread.ofPlatform().name("native-worker").start(() ->
System.out.println("Platform? " + !Thread.currentThread().isVirtual()));
p.join();
}
}开销对比
平台线程开销较大:
- 每个线程预留约 1 MB 的栈空间
- 创建速度慢
- 数量限制在几千个
虚拟线程开销很低:初始栈很小、创建速度快,可行数量达到数百万。
输入输出密集型工作
如果您的任务大部分时间都在等待网络、磁盘或数据库,虚拟线程的优势会非常明显。
当一个虚拟线程阻塞时,其载体线程会被释放去运行其他线程,因此少量 OS 线程就能服务数千个请求。
CPU 密集型工作
对于始终不会阻塞的纯计算任务,虚拟线程不会带来加速。您会受到核心数的限制。
在这种情况下,使用大小与处理器数量相匹配的固定线程池才是正确的选择。
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws Exception {
int cores = Runtime.getRuntime().availableProcessors();
try (ExecutorService cpu = Executors.newFixedThreadPool(cores)) {
Future<Long> f = cpu.submit(() -> {
long s = 0;
for (long i = 0; i < 1_000_000L; i++) s += i;
return s;
});
System.out.println("Cores: " + cores + ", sum: " + f.get());
}
}
}模拟阻塞
这段代码展示了许多虚拟线程同时休眠(作为阻塞式输入输出的替代情形)。请试着想象一下让 10,000 个平台线程做同样的事情。
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
AtomicInteger done = new AtomicInteger();
try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
exec.submit(() -> {
try { Thread.sleep(50); } catch (InterruptedException e) {}
done.incrementAndGet();
});
}
}
System.out.println("Finished blocking tasks: " + done.get());
}
}守护状态
虚拟线程始终是守护线程,不能改为非守护线程。平台线程默认继承创建者的守护状态,但也可以显式设置。
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread v = Thread.ofVirtual().unstarted(() -> {});
Thread p = Thread.ofPlatform().unstarted(() -> {});
System.out.println("virtual daemon: " + v.isDaemon());
System.out.println("platform daemon: " + p.isDaemon());
}
}忽略优先级
虚拟线程始终报告 NORM_PRIORITY 优先级,设置优先级不会产生任何影响。调度由 JVM 处理,而不是由 OS 调度器处理。
public class Main {
public static void main(String[] args) {
Thread v = Thread.ofVirtual().unstarted(() -> {});
v.setPriority(Thread.MAX_PRIORITY);
System.out.println("Priority is still: " + v.getPriority());
}
}选择指南
一个实用的经验法则:
- 有大量任务需要等待输入输出?使用虚拟线程。
- 有受 CPU 限制的繁重计算?使用平台线程固定线程池。
- 需要进行操作系统级线程调优(优先级、亲和性)?使用平台线程。
两者可以共存
您不必为整个程序只选择一种线程。典型应用会使用虚拟线程处理请求,同时使用小型平台线程池处理 CPU 密集型部分。
两者共享相同的 Thread 接口,因此可以无缝混用。
迁移提示
迁移输入输出负载较高的服务时,最小的改动是替换执行器:将固定线程池或缓存线程池替换为 newVirtualThreadPerTaskExecutor()。
但请注意线程固定和 ThreadLocal 滥用问题,下一课将介绍这些内容。
快速检验
请选择虚拟线程能带来最明显收益的工作负载。
回顾
您比较了两种线程模型:
- 平台线程:开销大、由 OS 支持,最适合 CPU 密集型工作和操作系统级调优
- 虚拟线程:开销低、由 JVM 管理、始终是守护线程,最适合输入输出密集型并发
- 两者可以共存并共享相同的接口
下一步:线程固定和 ThreadLocals 带来的陷阱。
常见问题解答
「平台线程与虚拟线程」课时是免费的吗?
是的 — 「平台线程与虚拟线程」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「平台线程与虚拟线程」这节课中我会学到什么?
了解各自适用的场景 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「平台线程与虚拟线程」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 什么是虚拟线程
- 创建虚拟线程
- 平台线程与虚拟线程
- 陷阱:固定与 ThreadLocals