一、版本定位与发布策略

先把四个版本的定位讲清楚:

发布节奏的变化 是理解 Java 生态的关键:

• JDK 8 之前:大版本之间间隔 2-3 年,功能堆积严重,延期是常态(JDK 9 跳票了三年)

• JDK 9 之后:切换到 6 个月一个版本的 train model,每年 3 月和 9 月发版

• LTS 节奏:最初是每 3 年一个 LTS(8 → 11 → 17),从 JDK 17 开始改为每 2 年(17 → 21 → 25)

这个策略变化直接影响了我们的技术选型。很多团队在 JDK 8 上停留了近十年,核心原因就是 JDK 9 到 JDK 16 期间没有 LTS 版本值得冒险升级。JDK 17 是第一个真正让大家觉得"该升了"的版本。

关于许可证问题说两句:JDK 8u211 之后,Oracle JDK 商用需要付费。JDK 17 开始 Oracle 恢复了 NFTC(No-Fee Terms and Conditions)许可,可以免费商用。但很多公司已经转向了 Adoptium(Eclipse Temurin)、Amazon Corretto、Azul Zulu 等发行版,这些发行版在各个版本上都是免费的。

二、语言特性演进

2.1 JDK 8:Lambda 与 Stream 的函数式革命

JDK 8 是 Java 历史上最重大的语言层面变革。它一次性引入了 Lambda、Stream、Optional、新日期 API 四个核心特性,直接改变了 Java 的编程范式。

Lambda 表达式和函数式接口

JDK 8 之前写一个线程排序:

JDK 8 之后:

Lambda 的底层实现值得了解:它不是匿名内部类的语法糖。编译器用 invokedynamic 指令在运行时通过 LambdaMetafactory 生成实现类,避免了匿名内部类在编译期生成大量 .class 文件的问题。你可以用 javap -c -p 看到这个区别:

Stream API

Stream 的核心设计是惰性求值(lazy evaluation)。中间操作(filter、map、flatMap)不会立即执行,只有终端操作(collect、forEach、reduce)触发时才会一次性处理整个管道:

关于 parallel stream,我的建议是:在 Web 应用中极少使用它。parallel stream 底层使用 ForkJoinPool.commonPool(),这个线程池是全局共享的。如果你在一个 HTTP 请求处理中使用 parallel stream 处理一个耗时操作,会影响其他请求中 parallel stream 的执行。我们曾因此在生产环境遇到过接口超时。

上图展示了 Stream 管道的完整处理流程——从数据源到中间操作(惰性)再到终端操作(触发执行),以及 parallel stream 的 Fork-Join 分治模型。

Optional

java.time API

终于替掉了灾难般的 java.util.Date 和 Calendar:

2.2 JDK 9-16 的关键过渡特性

这一段很多人会直接跳过,但实际上 JDK 9-16 的过渡特性在后续 LTS 版本中全部转正了。不了解它们的演化过程,你用 JDK 17/21 的时候会觉得这些特性"凭空冒出来"。

JDK 9:模块系统(Project Jigsaw

JDK 9 还引入了集合工厂方法、JShell、接口私有方法:

JDK 10:局部变量类型推断(var)

JDK 11:String 增强、HttpClient 标准化

JDK 14:Records(预览)、instanceof 模式匹配(预览)

JDK 15:Text Blocks

2.3 JDK 17:语言特性的成熟期

JDK 17 把 JDK 14-16 期间预览的特性全部转正,形成了一个完整的"现代 Java"特性集。

Sealed Classes(JEP 409)

Sealed classes 限定了一个类的子类范围,配合 pattern matching 使用时,编译器可以做穷举检查:

图展示了 Sealed Classes 的继承约束——sealed 接口只允许指定的子类实现,final 子类不能再被继承,non-sealed 子类则开放扩展。

Pattern Matching for instanceof(JEP 394)

JDK 17 其他值得关注的变化:

• 移除了 AOT 编译器和 JIT 编译器的 Graal 接口(JEP 410)——这意味着如果要用 GraalVM,需要单独安装

• 强封装 JDK 内部 API(JEP 403)——--illegal-access=permit 不再生效

• 移除了 RMI Activation(JEP 407)

• 恢复始终严格的浮点语义(JEP 306)

2.4 JDK 18-20 的过渡

这三个非 LTS 版本为 JDK 21 的两个杀手级特性做了铺垫:

• JDK 18:默认字符编码改为 UTF-8(JEP 400),Simple Web Server(JEP 408)

• JDK 19:Virtual Threads 首次预览(JEP 425),Structured Concurrency 孵化(JEP 428)

• JDK 20:Scoped Values 孵化(JEP 429),Record Patterns 二次预览(JEP 432)

2.5 JDK 21:并发模型的革命

JDK 21 是继 JDK 8 之后 Java 平台最重大的一次变革。Virtual Threads 的正式发布,从根本上改变了 Java 的并发编程模型。

Virtual Threads(JEP 444)

Virtual Thread 不是"轻量级线程"这么简单的描述能概括的。它的本质是将线程从操作系统资源变成了 JVM 管理的资源。

传统 Platform Thread 的问题:

• 每个线程占用约 1MB 栈内存(可配置,默认 -Xss1m)

• 线程创建和销毁涉及系统调用(pthread_create/pthread_exit)

• 上下文切换成本高(内核态切换)

• 一个 JVM 进程能创建的线程数通常在几千到几万

Virtual Thread 的实现机制:

• 由 JVM 管理,不直接映射到 OS 线程

• 使用 Continuation 保存和恢复执行状态

• 在遇到阻塞操作时(I/O、sleep、锁等),自动从 carrier thread(载体线程)上卸载(unmount)

• 阻塞解除后,调度到任意可用的 carrier thread 上继续执行

• 栈空间按需增长,初始只有几百字节

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐