不可变类天然线程安全,因其满足三条件:状态创建后不可修改、所有字段为private final、构造中this不逸出;通过封装(私有字段、无setter、防御性拷贝、final类)确保状态不可变,从而消除可见性、原子性和竞态条件风险。

封装通过不可变类设计保证线程安全,核心在于“状态不可变 + 正确发布”,让多线程无需同步也能安全共享对象。
不可变类的三个硬性条件
一个类要成为真正意义上的不可变类,必须同时满足:
- 对象创建后,所有状态(字段值)不能再被修改
- 所有字段都声明为 final(基本类型值不可变;引用类型则保证引用不重定向)
- 对象在构造过程中,this 引用不能逸出(比如不在构造器里启动线程、不将 this 传给外部方法或静态集合)
封装如何支撑不可变性
封装不是可选技巧,而是不可变的前提:
- 私有字段:所有状态字段必须是 private,防止外部直接赋值或修改内部结构
- 无 setter 方法:不提供任何修改状态的公共方法(如 setXxx())
- 防御性拷贝:若字段是可变对象(如 Date、ArrayList、HashMap),构造器中接收时需深拷贝;getter 中返回副本而非原始引用
- final 类:将类本身声明为 final,避免子类通过继承破坏不可变契约
典型不可变类的设计示例
以自定义坐标点为例:
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
// 没有 setX / setY,没有修改逻辑
}
多个线程可同时读取任意 Point 实例,无需加锁——因为它的状态从诞生起就固定了,也不存在竞态条件。
为什么不可变类天然线程安全
根本原因在于:线程安全的本质是消除“可见性”和“原子性”风险。而不可变类绕开了这两个问题:
- 无可见性问题:final 字段的写操作具有 happens-before 语义,确保其他线程看到的是完全构造好的状态
- 无原子性问题:没有复合修改操作(如先查再改),所有访问都是纯读,单次读取本身就是原子的
- 无竞态条件:状态无法改变,自然不存在“读到一半被改”的中间态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











