You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求Java构造器中this逃逸(最后语句)导致异常输出的示例程序

构造器中this逃逸导致未完全构造对象的可复现示例

你的原代码之所以总是输出42,是因为调用了t.join(),强制主线程等待子线程执行完毕才继续,子线程必然能看到构造器中已经完成的state=42赋值,无法复现未完全构造的问题。

以下是能大概率复现非预期输出的示例:

public class ThisEscapeDemo {
    private int state;

    public ThisEscapeDemo() {
        // 构造器内的模拟耗时操作,放大指令重排的概率
        for (int i = 0; i < 10000; i++) {
            // 空循环占用CPU,给JVM指令重排留机会
        }
        
        state = 42;
        
        // 构造器最后一步:this引用逃逸到新线程
        new Thread(() -> {
            // 可能读取到state的默认初始值0,而非预期的42
            System.out.println("线程读取到的state值:" + state);
        }).start();
    }

    public static void main(String[] args) {
        // 多次运行实例,增加复现概率
        for (int i = 0; i < 100; i++) {
            new ThisEscapeDemo();
        }
    }
}

为什么会出现非预期值?

  • 无线程等待:构造器启动子线程后没有调用join(),主线程会继续执行(甚至直接结束),子线程可能在构造器完成state=42赋值前就开始执行。
  • JVM指令重排序:Java虚拟机允许在不违反单线程语义的前提下重排指令。构造器中state=42的赋值操作,可能被重排到对象实例化(即this引用可用)之后,导致子线程拿到的是未完成赋值的对象,读取到state的默认值0。
  • 模拟耗时操作:空循环的作用是占用CPU时间,让子线程有更多机会在state赋值前调度执行,提升复现概率。

如果将state声明为volatile,会插入内存屏障阻止指令重排,就能避免这种问题,确保子线程看到的是已初始化的state值。

内容的提问来源于stack exchange,提问作者Otto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:25:19