Record天生线程安全,因其字段默认private final且构造后不可变,消除了写-写冲突和可见性问题;但需确保字段类型本身不可变,如用List.of()而非ArrayList。

Record 类本身不提供额外的线程同步机制,但它的不可变性天然保障了线程安全——只要字段值在构造后不再改变,多个线程可自由读取,无需加锁、无需 volatile、无需内存屏障。
为什么 Record 天生线程安全
Record 的每个字段默认是 private final,编译器强制在构造时完成初始化,且禁止后续修改。这种设计从根源上消除了“写-写冲突”和“写-读可见性”问题:
- 所有字段不可重赋值,状态无法被任何线程篡改
- final 字段的初始化语义保证了安全发布(Safe Publication),其他线程看到的对象必然是完全构造好的
- 没有 setter、没有可变集合字段(除非显式使用可变类型,需注意防御)
关键前提:字段类型也得是不可变的
Record 的线程安全性依赖于其组件类型的“实质不可变”。若字段是 ArrayList 或普通数组,仍可能被外部修改,破坏整体不可变契约:
- ✅ 推荐:用
List.of()、Set.of()、ImmutableList等不可变集合 - ✅ 推荐:用
String、LocalDateTime(不可变)、record嵌套 record - ❌ 风险:直接存
new ArrayList()或int[],外部可修改其内容
与传统可变 DTO 的并发对比
对比一个手动写的可变 User 类和等价的 Record:
- 可变类:多线程读写同一实例需 synchronized / ReentrantLock / CopyOnWriteArrayList,否则易出现脏读、丢失更新
- Record 类:作为函数式数据载体,每次“变更”都应创建新实例(如
user.withAge(26)),旧实例继续安全共享 - 实际效果:避免锁竞争、消除死锁可能、降低 GC 压力(短生命周期对象更易回收)
在高并发场景中的典型用法
Record 不是万能锁替代品,而是配合不可变范式构建更健壮的并发模型:
- 用作消息体:Kafka 消息、RPC 请求/响应、事件溯源中的事件对象
- 作为缓存键:因
hashCode和equals稳定可靠,适合做 ConcurrentHashMap 的 key - 配合虚拟线程(JDK 21+):大量轻量 Record 实例可高效流转,无共享状态争用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











