这是「Java 从基础到实战」系列的第 14 篇,阶段二「进阶硬核」收官。本文精选 JDK 17/21 两个 LTS 版本最值得马上用起来的特性:Record、密封类、模式匹配 switch,压轴是虚拟线程 vs 传统线程池的万级任务压测对比。前三节 JDK 17 可跑,虚拟线程需 JDK 21。
前言
很多团队还停在「Java 8 语法 + JDK 17 运行」的状态,白白浪费了新版本的表达力。本文每个特性都用「旧写法 → 新写法」对照展示,看完就能在项目里用。
环境准备
| 软件 | 版本 |
|---|---|
| JDK | 17(虚拟线程部分需 21,IDEA 中 File → Project Structure → SDK 可再添加一个 JDK 21) |
| IntelliJ IDEA | Community 社区版 |
在 java-basics 项目中新建包 modern。
特性 1:Record —— 一行顶五十行的数据类
旧写法 ❌(Java 8 时代的 DTO):
public class UserDto { |
新写法 ✅(JDK 16+):
package modern; |
一行自动获得:全参构造器、id()/name() 访问器、基于全字段的 equals/hashCode、可读的 toString。还能加校验和静态工厂:
public record UserDto(Long id, String name) { |
适用边界:不可变的数据载体(DTO、VO、配置项、Map 的复合 key)。要可变字段、要继承的场景仍用普通类。
特性 2:密封类 —— 把继承关系管起来
需求:支付结果只可能是「成功 / 失败 / 处理中」三种,不允许别人再扩展。旧写法只能靠文档约定;新写法(JDK 17)用 sealed 在编译期锁死:
package modern; |
配合 JDK 21 的模式匹配 switch,分支处理优雅且编译器强制穷尽:
package modern; |
预期输出:
支付成功: NO123,金额 9900 分 |
特性 3:其他即拿即用的小甜点
// 文本块(JDK 15+):告别字符串拼接 SQL/JSON |
特性 4(压轴):虚拟线程 —— JDK 21 的王牌
平台线程(传统线程)1:1 映射操作系统线程,默认栈 1MB,几千个就到极限。虚拟线程由 JVM 调度,栈按需增长(初始约几 KB),阻塞时自动让出底层线程,百万级也不在话下。IO 密集型任务是它的主场。
压测:10 000 个任务,每个模拟 100ms 的 IO 等待(需 JDK 21 运行):
package modern; |
笔者机器实测输出:
平台线程池(200) 完成 10000 个任务耗时: 5183 ms |
20 倍差距。原理:线程池只有 200 个工人,10 000 个 100ms 任务至少要 50 批 ≈ 5 秒;虚拟线程直接开 10 000 个,全部并行等待,理论下限就是 100ms + 调度开销。
使用姿势就一句话:Executors.newVirtualThreadPerTaskExecutor(),不要池化虚拟线程(它创建成本极低,池化反而画蛇添足)。
常见坑
坑 1:Record 当 JPA/MyBatis 实体用
错误示范 ❌:public record User(Long id, String name) 映射数据库表。ORM 框架需要无参构造 + setter 来回填字段,Record 全不可变,直接报错或字段全空。
正确写法:实体类用普通类,对外传输的 DTO 用 Record ✅。
坑 2:虚拟线程里跑 CPU 密集任务
错误认知 ❌:「虚拟线程快,什么任务都换成它」。
正确理解 ✅:虚拟线程只在阻塞等待(IO、sleep、锁)时产生收益;纯计算任务底层还是那几个 CPU 核心,换虚拟线程零提升甚至更慢。CPU 密集任务继续用 newFixedThreadPool(核数)。
坑 3:虚拟线程 + synchronized 长临界区导致「钉住」
错误示范 ❌:虚拟线程在 synchronized 块内做 IO——JDK 21 中这会把虚拟线程「钉」在底层平台线程上无法让出(pinning),并发优势全失。
正确写法:虚拟线程环境下的长临界区用 ReentrantLock 替代 synchronized ✅(第 8 篇的知识闭环了)。JDK 24 起该限制已被移除,但 21 上仍需注意。
小结
- ✅ Record:一行数据类,DTO 场景无脑用
- ✅ sealed + 模式匹配 switch:受控继承 + 编译期穷尽检查
- ✅ 文本块 / instanceof 模式匹配 / switch 表达式:即拿即用
- ✅ 虚拟线程:IO 密集场景 20 倍吞吐,
newVirtualThreadPerTaskExecutor一行开启
阶段二「进阶硬核」完结 🎉。下一篇进入阶段三「生态与框架」:《Maven 从入门到熟练:依赖管理、多模块、常用命令速查》,敬请期待。
上一篇:《Java 网络编程:从 Socket 到手写一个简易 HTTP 服务器》
本系列完整目录见博客「技术博文」分类。
💬 评论