核心是阻止this引用逸出——只要其他线程拿不到对象引用,就不可能读到未完成初始化的状态。构造函数中禁止暴露this、启动线程、使用匿名内部类或存入共享结构;应使用final字段、安全发布(volatile/同步块/静态初始化器)和防御性拷贝保障线程安全。

核心是阻止 this 引用逸出——只要其他线程拿不到对象引用,就不可能读到未完成初始化的状态。这不是等字段赋完值的问题,而是确保“引用不可见”。
构造函数里别暴露 this
这是最直接、最高危的源头。一旦把 this 传出去,哪怕只是存进静态容器、注册监听器、启动新线程或创建匿名内部类,外部线程就可能立刻访问一个半成品对象。
- 禁止在构造函数中启动线程(包括
new Thread(...).start()) - 避免用匿名内部类绑定回调,它隐式持有了外部
this - 不要把
this放入全局 Map、List、事件总线等共享结构中 - 若必须建立关联,改用延迟方式:先完成构造,再调用
init()或start()方法显式注册
用 final 字段 + 正确构造保障可见性
Java 内存模型(JMM)对 final 字段有特殊保证:只要构造函数正常结束,其他线程看到该对象时,所有 final 字段一定已初始化完毕且可见。
- 把关键状态字段声明为
private final - 确保它们只在构造函数内完成赋值(不能在 init() 中补赋)
- 注意:这个保证仅在
this没逸出的前提下生效
安全发布对象引用
对象构造完了,还得让其他线程“安全地看到它”。直接赋值给静态变量或共享字段仍可能因重排序导致问题。
立即学习“Java免费学习笔记(深入)”;
- 写入
volatile变量:如public static volatile Service instance; - 用
AtomicReference包装并调用set() - 在同步块内写入共享变量,读取也必须在同一锁下进行
- 静态初始化器(
static {})天然线程安全,适合单例或配置对象
防御性拷贝与不可变封装
即使对象本身构造完成,若通过 public 方法返回可变内部对象(如数组、ArrayList),外部仍能绕过封装修改状态,相当于间接暴露了未受控的中间态。
- 返回集合时用
Collections.unmodifiableList()或new ArrayList(original) - 返回数组时调用
clone(),别直接返回原始引用 - 内部字段尽量用不可变类型(String、Integer、LocalDateTime),或深拷贝可变对象(如 Date、自定义 Bean)
不复杂但容易忽略。关键不在“做了什么”,而在“没让别人提前拿到什么”。


















