JDK 8、JDK 17 和 JDK 21 中 Java 多线程实现方式总结(2025 最新全网最全教程)
·
JDK 8、JDK 17 和 JDK 21 中 Java 多线程实现方式总结(2025 最新全网最全教程)
本文针对 JDK 8、JDK 17 和 JDK 21 在 Java 多线程实现方式上的演进进行梳理,逐版本展示典型用法,深入对比优缺点和适用场景,帮助你快速选型。
引言
在 Java 生态中,多线程一直是构建高并发、高性能应用的核心手段。从最早的 Thread 类和 Runnable 接口到最新的虚拟线程与结构化并发,不同 JDK 版本不断丰富和简化编程模型。本篇博客将分三个阶段(JDK 8、JDK 17、JDK 21)深入剖析各种方案的用法、优缺点及适用场景。

目录
JDK 8 经典多线程方案
1. 继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
System.out.println("[Thread] 计数:" + i);
}
}
}
public class TestThread {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start(); // 启动新线程,执行 run()
for (int i = 1; i <= 20; i++) {
System.out.println("[Main] 计数:" + i);
}
}
}
- 优点:使用简单,上手快。
- 缺点:Java 单继承,线程类无法再扩展其他类;任务与线程耦合;无返回值。
2. 实现 Runnable 接口
class MyTask implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
System.out.println("[Runnable] 计数:" + i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
Thread t = new Thread(new MyTask());
t.start();
for (int i = 1; i <= 20; i++) {
System.out.println("[Main] 计数:" + i);
}
}
}
- 优点:任务与线程分离,可复用任务类;可多继承其他类。
- 缺点:无返回值;需手动管理线程对象。
3. 使用 Callable + Future
import java.util.concurrent.*;
public class TestCallable {
public static void main(String[] args) throws Exception {
Callable<Integer> c = () -> {
int sum = 0;
for (int i = 1; i <= 50; i++) sum += i;
return sum;
};
FutureTask<Integer> future = new FutureTask<>(c);
Thread t = new Thread(future);
t.start();
Integer result = future.get(); // 阻塞等待
System.out.println("sum = " + result);
}
}
- 优点:支持返回值和异常。
- 缺点:相对复杂,需要手动包装。
4. 基于 ExecutorService 的线程池
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
Runnable task = () -> {
for (int i = 1; i <= 20; i++) {
System.out.println("[Pool] 计数:" + i);
}
};
pool.submit(task);
pool.shutdown();
}
}
- 优点:线程可复用,避免频繁创建销毁;灵活配置线程池参数。
- 缺点:JDK 8 的
Executors工厂方法对队列、拒绝策略等缺乏精细控制。
JDK 17 异步与并行编程利器
1. CompletableFuture
import java.util.concurrent.*;
public class TestCompletableFuture {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
int sum = 0;
for (int i = 1; i <= 50; i++) sum += i;
return sum;
});
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
int sum = 0;
for (int i = 51; i <= 100; i++) sum += i;
return sum;
});
Integer total = f1.thenCombine(f2, Integer::sum).get();
System.out.println("total = " + total);
}
}
- 优点:链式编程、异常处理、非阻塞、可组合。
- 缺点:API 学习曲线稍陡;链式过长略显冗余。
2. 并行流(Parallel Stream)
import java.util.stream.IntStream;
public class TestParallelStream {
public static void main(String[] args) {
int total = IntStream.rangeClosed(1, 100)
.parallel() // 并行执行
.sum();
System.out.println("parallel sum = " + total);
}
}
- 优点:一行代码开启多核并行计算。
- 缺点:适合无状态数据处理;I/O、状态更新场景需谨慎。
3. 增强的线程池用法
ThreadPoolExecutor pool = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60L, TimeUnit.SECONDS, // keepAliveTime
new LinkedBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy()
);
- 优点:可精细控制队列、拒绝策略。
- 缺点:参数较多,需要根据业务调优。
JDK 21 虚拟线程与结构化并发
1. 虚拟线程(Virtual Threads)
public class TestVirtualThread {
public static void main(String[] args) throws InterruptedException {
// 创建并启动 1000 个虚拟线程
for (int i = 0; i < 1000; i++) {
Thread.startVirtualThread(() -> {
System.out.println(Thread.currentThread() + " 执行任务");
});
}
Thread.sleep(1000); // 等待所有任务完成
}
}
- 优点:开销极低,可轻松支持数万/百万并发;与传统线程一致的编程模型。
- 缺点:少数老库对
ThreadLocal兼容性需验证。
2. 结构化并发(Structured Concurrency)
import java.util.concurrent.*;
import jdk.incubator.concurrent.StructuredTaskScope;
public class TestStructuredConcurrency {
public static void main(String[] args) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<Integer> f1 = scope.fork(() -> computeSum(1, 50));
Future<Integer> f2 = scope.fork(() -> computeSum(51, 100));
scope.join(); // 等待所有子任务完成
scope.throwIfFailed(); // 失败即抛
int total = f1.resultNow() + f2.resultNow();
System.out.println("structured total = " + total);
}
}
static int computeSum(int a, int b) {
int s = 0;
for (int i = a; i <= b; i++) s += i;
return s;
}
}
- 优点:任务生命周期与作用域绑定;自动管理一组任务的失败和取消。
- 缺点:需导入孵化模块;API 仍在演进。
特性对比与选型建议
| 特性/版本 | JDK 8 | JDK 17 | JDK 21 |
|---|---|---|---|
| 线程模型 | 平台线程 | 平台线程 | 平台线程 + 虚拟线程 |
| 任务定义 | Thread/Runnable/Callable |
CompletableFuture/并行流 |
虚拟线程 + 结构化并发 |
| 返回 & 异常 | FutureTask |
CompletableFuture |
同 JDK 17 + 结构化异常管理 |
| 可扩展性 | 手动调优线程池 | 并行流 & 异步易扩展 | 数万线程无忧;任务隔离更优 |
| 使用复杂度 | 中等(API 零散) | 较高(链式 API),易错 | 简洁(虚拟线程 & 统一模型) |
| 最佳场景 | 少量固定线程、简单并发 | 异步组合、批量并行计算 | 超高并发 I/O 密集型服务 |
- JDK 8:优先使用线程池,避免频繁创建和销毁;需返回值请选择
Callable。 - JDK 17:推荐
CompletableFuture构建异步流水线,并行流做大数据批量计算,必要时手动配置ThreadPoolExecutor。 - JDK 21:立即试用虚拟线程消除数量瓶颈;对复杂任务组使用结构化并发获得更安全的失败语义。
Mermaid 可视化概览
结语
Java 多线程模型历经十余年演进,从原始的 Thread 与 Runnable,到现代的异步及大规模并发支持。了解各版本特性,结合业务需求与性能指标,才能设计出既稳定又高效的并行系统。希望本篇博客能助你在 JDK 8、JDK 17、JDK 21 的多线程世界里游刃有余,写出既简洁又强悍的并行代码。
更多推荐


所有评论(0)