java - 即时编译器如何优化 Java 并行流?

标签 java parallel-processing jvm java-stream jit

前段时间一个有趣的question被问到:

Can (a == 1 && a == 2 && a == 3) evaluate to true in Java?

我决定证明使用 Java 8 Stream API(准确地说是并行流)是可行的。这是我在极少数情况下有效的代码:

class Race {
    private static int a;

    public static void main(String[] args) {
        IntStream.range(0, 100_000).parallel().forEach(i -> {
            a = 1;
            a = 2;
            a = 3;
            testValue();
        });
    }

    private static void testValue() {
        if (a == 1 && a == 2 && a == 3) {
            System.out.println("Success");
        }
    }
}

然后我想,也许是因为潜在的 JIT 编译器优化?因此,我尝试使用以下 VM 选项运行代码:

-Djava.compiler=NONE

我禁用了 JIT,成功案例的数量显着增加!

即时编译器如何优化并行流,以便优化可能影响上述代码执行?

最佳答案

流并不重要。同样的效果可以用两个简单的线程观察到,如 this answer .

a 不是volatile 时,JIT 编译器可以优化(而且它确实做到了!)连续赋值。

    a = 1;
    a = 2;
    a = 3;

转化为

    a = 3;

此外,JIT 编译器还将 if (a == 1 && a == 2 && a == 3) 优化为 if (false) 然后安全地删除整个 testValue() 调用作为死代码。

让我们看看为 lambda 生成的程序集。
要打印编译后的代码,我使用 -XX:CompileCommand=print,Race::lambda$main$0

  # {method} {0x000000001e142de0} 'lambda$main$0' '(I)V' in 'Race'
  # parm0:    rdx       = int
  #           [sp+0x20]  (sp of caller)
  0x00000000052eb740: sub     rsp,18h
  0x00000000052eb747: mov     qword ptr [rsp+10h],rbp  ;*synchronization entry
                                                ; - Race::lambda$main$0@-1 (line 8)

  0x00000000052eb74c: mov     r10,76b8940c0h    ;   {oop(a 'java/lang/Class' = 'Race')}
  0x00000000052eb756: mov     dword ptr [r10+68h],3h  ;*putstatic a
                                                ; - Race::lambda$main$0@9 (line 10)

  0x00000000052eb75e: add     rsp,10h
  0x00000000052eb762: pop     rbp
  0x00000000052eb763: test    dword ptr [3470000h],eax
                                                ;   {poll_return}
  0x00000000052eb769: ret

除了方法 prologue 和 eplilogue 之外,只有一条指令存储值 3:

  mov     dword ptr [r10+68h],3h  ;*putstatic a

因此,一旦方法被编译,System.out.println 永远不会发生。当您看到“成功”时,那些罕见的情况发生在解释期间,此时代码尚未进行 JIT 编译。

关于java - 即时编译器如何优化 Java 并行流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48688363/

相关文章:

java - Android Studio 的 .alias 文件类型?

php - GNU Parallel 从网页运行

scala - 从 RAM 磁盘运行所有内容会加快 scala 编译时间吗?

java - 发布/订阅模型中事件回调的 Scala 初始化

scala - Scala(最新 2.10)与 Groovy++(最新 0.9.1?)的比较

java - 如何在 java 中准备一个字符串,该字符串最终将传递到 SQL 中进行搜索

java - 几个 jbutton 的随机颜色

java - 如何使用 Java Rally API 获取给定缺陷的讨论

c - for 循环中的迭代变量错误 : C program, OpenMP

Java 11 从 8 个并行流升级引发 ClassNotFoundException