Java 8(发布于2014年3月)之后的版本如下,列出主要长期支持(LTS)版本和非LTS版本(截至2025年6月10日):
LTS版本(长期支持)
-
Java 11(2018年9月):引入模块化系统增强、HTTP客户端API、局部变量类型推断(
var
)等。 -
Java 17(2021年9月):引入密封类、记录类(Records)、模式匹配、增强的垃圾回收(如ZGC改进)等。
-
Java 21(2023年9月):引入虚拟线程(Project Loom)、结构化并发、序列化集合等。
非LTS版本(短期支持,6个月更新周期)
-
Java 9(2017年9月):引入模块化系统(JPMS)、JShell、集合工厂方法等。
-
Java 10(2018年3月):局部变量类型推断(
var
)、G1垃圾回收器改进。 -
Java 12(2019年3月):Switch表达式预览、Shenandoah GC。
-
Java 13(2019年9月):文本块预览、动态CDS归档。
-
Java 14(2020年3月):Switch表达式正式化、记录类预览。
-
Java 15(2020年9月):文本块正式化、密封类预览。
-
Java 16(2021年3月):记录类正式化、模式匹配instanceof。
-
Java 18(2022年3月):简单Web服务器、UTF-8默认编码。
-
Java 19(2022年9月):虚拟线程预览、结构化并发预览。
-
Java 20(2023年3月):Switch模式匹配预览、外部函数和内存API。
最新版本
-
Java 22(2024年3月):非LTS,包含外部函数和内存API正式化、虚拟线程改进等。
-
Java 23(2024年9月):非LTS,最新特性包括模块化增强、隐式类、原始类型改进等。
说明
-
LTS版本(Java 11、17、21)通常用于生产环境,获得更长时间的官方支持(通常至2026年或更久,具体取决于供应商如Oracle或OpenJDK社区)。
-
非LTS版本每6个月发布一次,适合早期采用者和测试新特性,但支持周期短(仅到下一个版本发布)。
-
Java 8之后采用**时间驱动发布模型**(每6个月一个新版本,3月和9月),由OpenJDK社区推动。
-
Java 24预计于2025年3月发布(非LTS),但截至2025年6月10日尚未正式发布。
java21新特性
Java 21 中引入的**虚拟线程(Project Loom)**、**结构化并发**和**序列化集合**的简要解释,结合其在 Java 8 及之后版本的背景,重点说明其作用和意义:
1. 虚拟线程(Project Loom)
-
定义:虚拟线程(Virtual Threads)是 Java 平台引入的轻量级线程模型,旨在简化并发编程,提高高并发场景下的性能。它们是 JVM 管理的线程,而不是直接映射到操作系统的原生线程。
-
引入版本:
-
预览:Java 19(2022年9月)、Java 20(2023年3月)
-
正式:**Java 21**(2023年9月)
-
-
作用:
-
高并发支持:虚拟线程允许创建数百万个线程(远超传统线程的几千个),适用于高并发任务,如 Web 服务器处理大量请求。
-
简化并发编程:开发者无需复杂的管理线程池或异步编程(如
CompletableFuture
),可以用简单的阻塞式代码(类似同步代码)实现高吞吐量。 -
低开销:虚拟线程由 JVM 调度,挂起/恢复时不占用操作系统线程,内存占用极低(几 KB 而非 MB)。
-
与现有代码兼容:支持现有同步 API(如
synchronized
、Thread.sleep
),无需重写代码。
-
-
典型场景:Web 服务器、微服务、任务并行处理。例如,一个 Web 应用可以为每个请求分配一个虚拟线程,简化代码逻辑,同时保持高性能。
-
代码示例:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { executor.submit(() -> { System.out.println("Running in a virtual thread: " + Thread.currentThread()); }); }
2. 结构化并发(Structured Concurrency)
-
定义:结构化并发是一种并发编程模型,旨在让并发任务以结构化的方式组织和管理,确保任务的生命周期清晰且可控,减少线程泄漏和复杂性。
-
引入版本:
-
预览:Java 19(2022年9月)、Java 20(2023年3月)
-
正式:**Java 21**(2023年9月)
-
-
作用:
-
任务层次管理:将并发任务组织成父子关系,子任务完成后自动返回父任务,类似代码块的嵌套结构。
-
错误处理:如果某个子任务失败,父任务可以捕获并处理异常,避免任务“失控”。
-
资源管理:通过
StructuredTaskScope
(如ShutdownOnFailure
或ShutdownOnSuccess
),确保任务完成后资源被正确清理。 -
简化并发代码:相比传统线程池或
ForkJoinPool
,结构化并发代码更直观,易于调试和维护。
-
-
典型场景:处理多个并行子任务(如调用多个 API 并汇总结果)时,确保任务按预期完成或失败。
-
代码示例:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> task1 = scope.fork(() -> "Result 1");
Future<String> task2 = scope.fork(() -> "Result 2");
scope.join(); // 等待所有任务完成
System.out.println(task1.resultNow() + ", " + task2.resultNow());
}
3. 序列化集合(Sequenced Collections)
-
定义:序列化集合(Sequenced Collections)是 Java 21 引入的新集合接口体系,统一了有序集合(如
List
、LinkedHashSet
)的操作,提供一致的 API 来访问和操作集合的首尾元素。 -
引入版本:**Java 21**(2023年9月,JEP 431)
-
作用:
-
统一接口:引入
SequencedCollection
、SequencedSet
和SequencedMap
接口,为所有有序集合提供标准方法,如getFirst
、getLast
、addFirst
、addLast
、reversed
等。 -
简化操作:开发者无需为不同集合类型(如
List
vsDeque
)使用不同的 API,减少学习成本。 -
向后兼容:现有集合类(如
ArrayList
、LinkedHashSet
、LinkedHashMap
)已实现这些新接口,无需修改代码。 -
支持反转视图:通过
reversed()
方法获取集合的反向视图,简化反向遍历。
-
-
典型场景:需要操作有序集合的首尾元素,或需要反向遍历集合时,如处理队列、栈或日志记录。
-
代码示例:
SequencedCollection<String> list = new ArrayList<>();
list.addFirst("First");
list.addLast("Last");
System.out.println(list); // [First, Last]
System.out.println(list.reversed()); // [Last, First]
与 Java 8 的关系
-
Java 8 引入了 Lambda 表达式、Stream API 和
CompletableFuture
,为并发编程奠定了基础,但仍依赖传统线程模型,复杂场景下代码复杂且性能受限。 -
虚拟线程和结构化并发是对 Java 8 并发模型的重大升级,简化了高并发场景的开发,性能更优。
-
序列化集合是对 Java 8 集合框架的增强,提供了更一致的 API,弥补了早期集合操作的不统一性。
总结
-
虚拟线程:通过轻量级线程简化高并发编程,适合高吞吐量场景。
-
结构化并发:以结构化方式管理并发任务,提升代码可读性和可靠性。
-
序列化集合:统一有序集合操作,简化首尾访问和反转逻辑。
以下针对 Java 21 的**虚拟线程(Project Loom)**、**结构化并发**和**序列化集合**,提供更详细的**代码示例**和**性能分析**,并结合 Java 8 及之后版本的背景。由于之前提到特斯拉温度过热保护,我会尽量用简洁的语言,并避免过于复杂的术语,同时确保内容清晰。
1. 虚拟线程(Project Loom)
代码示例
以下是一个模拟 Web 服务器处理 10,000 个并发请求的示例,比较虚拟线程和传统线程池的写法:
import java.util.concurrent.*;
import java.util.stream.IntStream;
public class VirtualThreadDemo {
public static void main(String[] args) throws InterruptedException {
// 模拟的任务:每个请求休眠 100ms
Runnable task = () -> {
try {
Thread.sleep(100);
System.out.println("Task done on: " + Thread.currentThread());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
// 使用虚拟线程
long startVirtual = System.currentTimeMillis();
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> executor.submit(task));
}
System.out.println("Virtual Threads: " + (System.currentTimeMillis() - startVirtual) + " ms");
// 使用传统线程池
long startPool = System.currentTimeMillis();
try (var executor = Executors.newFixedThreadPool(200)) {
IntStream.range(0, 10_000).forEach(i -> executor.submit(task));
}
System.out.println("Thread Pool: " + (System.currentTimeMillis() - startPool) + " ms");
}
}
性能分析
-
虚拟线程:
-
优点:
-
高并发:虚拟线程允许创建数百万线程,每个线程内存开销仅几 KB(对比传统线程的 ~1MB)。在上述示例中,10,000 个虚拟线程几乎无压力。
-
低调度开销:虚拟线程由 JVM 调度(基于
ForkJoinPool
的延续机制),挂起(如 I/O 等待)时不占用 OS 线程,CPU 利用率高。 -
运行时间:示例中,10,000 个任务(每个 100ms)通常在 ~150-200ms 完成,因为虚拟线程并行度极高。
-
-
缺点:
-
CPU 密集型任务:虚拟线程不适合长时间占用 CPU 的任务(如复杂计算),因为它们共享底层线程池(默认 CPU 核心数)。
-
调试复杂:大量虚拟线程可能增加堆栈跟踪的复杂性。
-
-
-
传统线程池:
-
瓶颈:受限于线程池大小(如 200),任务需排队,10,000 个任务可能需要 ~5,000ms(100ms * 10,000 / 200)。
-
内存开销:每个线程 ~1MB,200 个线程已占用 ~200MB 内存,高并发下易触发
OutOfMemoryError
。 -
适用场景:适合 CPU 密集型任务或需要精确控制线程数的场景。
-
-
对比:
-
虚拟线程在**高并发 I/O 密集型任务**(如 Web 服务器、数据库查询)中性能远超线程池,吞吐量可提高 10-100 倍。
-
虚拟线程简化代码,无需手动调优线程池大小,开发者只需关注业务逻辑。
-
2. 结构化并发(Structured Concurrency)
代码示例
以下是一个示例,模拟并行调用两个 API(任务),并汇总结果,展示结构化并发的清晰性和错误处理:
import java.util.concurrent.*;
public class StructuredConcurrencyDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
record Response(String api1, String api2) {}
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 模拟两个 API 调用
Future<String> api1 = scope.fork(() -> {
Thread.sleep(100); // 模拟延迟
return "Result from API 1";
});
Future<String> api2 = scope.fork(() -> {
Thread.sleep(150);
// 模拟失败:throw new RuntimeException("API 2 failed");
return "Result from API 2";
});
scope.join(); // 等待所有任务完成
scope.throwIfFailed(e -> new RuntimeException("Task failed", e)); // 处理异常
Response response = new Response(api1.resultNow(), api2.resultNow());
System.out.println(response);
}
}
}
性能分析
-
结构化并发:
-
优点:
-
并行效率:示例中,两个任务(100ms 和 150ms)并行执行,总时间接近 150ms,而非 250ms(串行)。
-
清晰生命周期:任务在
scope
内自动管理,完成后自动清理,无需手动关闭线程池。 -
错误处理:如果
api2
抛出异常,scope.throwIfFailed
确保异常被捕获,父任务可优雅处理。 -
内存效率:任务运行在虚拟线程或底层线程池上,资源占用低。
-
-
缺点:
-
复杂场景限制:目前 API 较为简单,适合层次分明的任务,动态任务调度仍需传统线程池。
-
学习曲线:开发者需熟悉
StructuredTaskScope
的使用方式。
-
-
-
与 Java 8 的对比:
-
Java 8 使用
CompletableFuture
实现类似功能,但代码复杂,需手动管理完成和异常:CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(100); return "Result from API 1"; } catch (Exception e) { throw new RuntimeException(e); } }); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(150); return "Result from API 2"; } catch (Exception e) { throw new RuntimeException(e); } }); CompletableFuture.allOf(future1, future2).join();
-
CompletableFuture
缺乏结构化管理,任务关系不清晰,异常处理繁琐。
-
-
结构化并发代码更直观,性能相当(并行时间接近),但开发效率更高。
-
3. 序列化集合(Sequenced Collections)
代码示例
以下示例展示如何使用 SequencedCollection
操作一个有序集合(如 ArrayList
),包括首尾操作和反转:
import java.util.*;
public class SequencedCollectionDemo {
public static void main(String[] args) {
SequencedCollection<String> list = new ArrayList<>();
list.addLast("Apple");
list.addLast("Banana");
list.addFirst("Orange");
System.out.println("Original: " + list); // [Orange, Apple, Banana]
System.out.println("First: " + list.getFirst()); // Orange
System.out.println("Last: " + list.getLast()); // Banana
System.out.println("Reversed: " + list.reversed()); // [Banana, Apple, Orange]
// 删除首元素
list.removeFirst();
System.out.println("After removeFirst: " + list); // [Apple, Banana]
}
}
性能分析
-
序列化集合:
-
优点:
-
一致性:
getFirst
、addLast
等方法在所有SequencedCollection
实现(如ArrayList
、LinkedList
、LinkedHashSet
)中行为一致,简化开发。 -
性能无损:新方法直接调用底层实现(如
ArrayList.get(0)
),无额外开销。示例中,getFirst
的时间复杂度为 O(1)(ArrayList
)。 -
反转视图高效:
reversed()
返回视图而非复制集合,内存开销极低(O(1)),适合频繁反向遍历。
-
-
缺点:
-
有限新功能:主要增强 API 一致性,未引入全新数据结构,功能增益有限。
-
特定场景限制:
LinkedList
的addFirst
为 O(1),但ArrayList
的addFirst
为 O(n),需选择合适实现。
-
-
-
与 Java 8 的对比:
-
Java 8 中,首尾操作依赖具体集合类:
List<String> list = new ArrayList<>(); list.add(0, "Orange"); // O(n) list.add("Apple"); list.get(0); // O(1) Collections.reverse(list); // O(n),
-
修改原集合
-
操作不统一(如
Deque
用addFirst
),反转需修改集合,性能和代码可读性较差。
-
-
序列化集合的 API 更简洁,
reversed()
提供高效视图,开发效率提升,性能相当或略优。
-
综合性能对比
特性 |
虚拟线程 |
结构化并发 |
序列化集合 |
主要优势 |
高并发 I/O 任务,吞吐量提升 10-100 倍 |
结构化任务管理,代码简洁 |
统一有序集合 API,高效视图 |
性能开销 |
内存低(KB/线程),调度高效 |
并行时间最优,资源清理自动 |
操作 O(1) 或 O(n),视实现 |
与 Java 8 对比 |
远超线程池和 |
优于 |
优于非统一集合操作 |
适用场景 |
Web 服务器、微服务 |
API 调用、任务聚合 |
队列、栈、日志处理 |