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

多线程数组可见性问题:不同长度数组为何执行结果不同?

线程可见性与JIT优化导致的差异行为解释

在Windows环境下运行下述代码时会出现两种不同结果:

  • 当线程t2检查数组全部200个元素时,程序最终会正常终止
  • 当t2只检查更少元素(比如前100个)时,程序会陷入无限循环

这段代码原本是用来演示线程间的内存可见性问题:线程t1对数组的赋值操作,线程t2无法感知,而通过volatile修饰数组可以解决该问题。

示例代码

public static void main(String[] args) throws InterruptedException {
    int[] arr = new int[200];
    for (int i=0; i<arr.length; i++) {
        arr[i] = 0;
    }
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        for (int i=0; i<arr.length; i++) {
            arr[i] = 1;
        }
    });
    Thread t2 = new Thread(() -> {
        while (true) {
            if (arr[0] == 1
                    || arr[1] == 1
                    || arr[2] == 1
                    || arr[3] == 1
                    || arr[4] == 1
                    || arr[5] == 1
                    || arr[6] == 1
                    || arr[7] == 1
                    || arr[8] == 1
                    || arr[9] == 1
                    || arr[10] == 1
                    || arr[11] == 1
                    || arr[12] == 1
                    || arr[13] == 1
                    || arr[14] == 1
                    || arr[15] == 1
                    || arr[16] == 1
                    || arr[17] == 1
                    || arr[18] == 1
                    || arr[19] == 1
                    || arr[20] == 1
                    || arr[21] == 1
                    || arr[22] == 1
                    || arr[23] == 1
                    || arr[24] == 1
                    || arr[25] == 1
                    || arr[26] == 1
                    || arr[27] == 1
                    || arr[28] == 1
                    || arr[29] == 1
                    || arr[30] == 1
                    || arr[31] == 1
                    || arr[32] == 1
                    || arr[33] == 1
                    || arr[34] == 1
                    || arr[35] == 1
                    || arr[36] == 1
                    || arr[37] == 1
                    || arr[38] == 1
                    || arr[39] == 1
                    || arr[40] == 1
                    || arr[41] == 1
                    || arr[42] == 1
                    || arr[43] == 1
                    || arr[44] == 1
                    || arr[45] == 1
                    || arr[46] == 1
                    || arr[47] == 1
                    || arr[48] == 1
                    || arr[49] == 1
                    || arr[50] == 1
                    || arr[51] == 1
                    || arr[52] == 1
                    || arr[53] == 1
                    || arr[54] == 1
                    || arr[55] == 1
                    || arr[56] == 1
                    || arr[57] == 1
                    || arr[58] == 1
                    || arr[59] == 1
                    || arr[60] == 1
                    || arr[61] == 1
                    || arr[62] == 1
                    || arr[63] == 1
                    || arr[64] == 1
                    || arr[65] == 1
                    || arr[66] == 1
                    || arr[67] == 1
                    || arr[68] == 1
                    || arr[69] == 1
                    || arr[70] == 1
                    || arr[71] == 1
                    || arr[72] == 1
                    || arr[73] == 1
                    || arr[74] == 1
                    || arr[75] == 1
                    || arr[76] == 1
                    || arr[77] == 1
                    || arr[78] == 1
                    || arr[79] == 1
                    || arr[80] == 1
                    || arr[81] == 1
                    || arr[82] == 1
                    || arr[83] == 1
                    || arr[84] == 1
                    || arr[85] == 1
                    || arr[86] == 1
                    || arr[87] == 1
                    || arr[88] == 1
                    || arr[89] == 1
                    || arr[90] == 1
                    || arr[91] == 1
                    || arr[92] == 1
                    || arr[93] == 1
                    || arr[94] == 1
                    || arr[95] == 1
                    || arr[96] == 1
                    || arr[97] == 1
                    || arr[98] == 1
                    || arr[99] == 1
                    || arr[100] == 1
                    || arr[101] == 1
                    || arr[102] == 1
                    || arr[103] == 1
                    || arr[104] == 1
                    || arr[105] == 1
                    || arr[106] == 1
                    || arr[107] == 1
                    || arr[108] == 1
                    || arr[109] == 1
                    || arr[110] == 1
                    || arr[111] == 1
                    || arr[112] == 1
                    || arr[113] == 1
                    || arr[114] == 1
                    || arr[115] == 1
                    || arr[116] == 1
                    || arr[117] == 1
                    || arr[118] == 1
                    || arr[119] == 1
                    || arr[120] == 1
                    || arr[121] == 1
                    || arr[122] == 1
                    || arr[123] == 1
                    || arr[124] == 1
                    || arr[125] == 1
                    || arr[126] == 1
                    || arr[127] == 1
                    || arr[128] == 1
                    || arr[129] == 1
                    || arr[130] == 1
                    || arr[131] == 1
                    || arr[132] == 1
                    || arr[133] == 1
                    || arr[134] == 1
                    || arr[135] == 1
                    || arr[136] == 1
                    || arr[137] == 1
                    || arr[138] == 1
                    || arr[139] == 1
                    || arr[140] == 1
                    || arr[141] == 1
                    || arr[142] == 1
                    || arr[143] == 1
                    || arr[144] == 1
                    || arr[145] == 1
                    || arr[146] == 1
                    || arr[147] == 1
                    || arr[148] == 1
                    || arr[149] == 1
                    || arr[150] == 1
                    || arr[151] == 1
                    || arr[152] == 1
                    || arr[153] == 1
                    || arr[154] == 1
                    || arr[155] == 1
                    || arr[156] == 1
                    || arr[157] == 1
                    || arr[158] == 1
                    || arr[159] == 1
                    || arr[160] == 1
                    || arr[161] == 1
                    || arr[162] == 1
                    || arr[163] == 1
                    || arr[164] == 1
                    || arr[165] == 1
                    || arr[166] == 1
                    || arr[167] == 1
                    || arr[168] == 1
                    || arr[169] == 1
                    || arr[170] == 1
                    || arr[171] == 1
                    || arr[172] == 1
                    || arr[173] == 1
                    || arr[174] == 1
                    || arr[175] == 1
                    || arr[176] == 1
                    || arr[177] == 1
                    || arr[178] == 1
                    || arr[179] == 1
                    || arr[180] == 1
                    || arr[181] == 1
                    || arr[182] == 1
                    || arr[183] == 1
                    || arr[184] == 1
                    || arr[185] == 1
                    || arr[186] == 1
                    || arr[187] == 1
                    || arr[188] == 1
                    || arr[189] == 1
                    || arr[190] == 1
                    || arr[191] == 1
                    || arr[192] == 1
                    || arr[193] == 1
                    || arr[194] == 1
                    || arr[195] == 1
                    || arr[196] == 1
                    || arr[197] == 1
                    || arr[198] == 1
                    || arr[199] == 1
            ) {
                break;
            }
        }
    });
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    System.out.println("finished");
}

现象原因解释

  1. 内存可见性基础问题
    Java内存模型中,每个线程拥有独立的工作内存,主存为所有线程共享。线程t1修改数组元素后,修改值不会立刻同步到主存;线程t2默认只会从自身工作内存读取数组值,不会主动去主存刷新,因此可能看不到t1的修改。

  2. JIT即时编译器的循环优化差异
    这是两种结果出现的核心原因:

    • 检查少量元素时:t2的循环体代码简短,JIT编译器会触发循环不变量优化——将数组的所有读取操作一次性缓存到CPU寄存器中,后续循环不再去主存重新读取数组值。哪怕t1已经把数组全部改为1,t2也只会读取寄存器里的旧值(全0),永远不会触发break,陷入无限循环。
    • 检查全部200个元素时:循环体代码量过大,超出了JIT编译器触发激进优化的阈值,JIT不会对这段代码做缓存优化。t2每次循环都会去主存读取数组元素,最终能看到t1修改后的1值,从而跳出循环,程序正常终止。
  3. volatile的解决原理
    给数组加上volatile修饰后,会强制:

    • 线程每次读取数组时必须从主存获取最新值
    • 线程修改数组后必须立刻把值同步到主存
    • 禁止JIT编译器对该数组的读取操作做缓存优化
      无论检查多少元素,t2都能及时感知到t1的修改,不会出现无限循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:27:04