测量时间间隔和无序执行

Abh*_*k S 5 java

我一直在阅读有关Java内存模型的信息,并且我知道编译器可以重新组织语句来优化代码。

假设我有以下代码:

long tick = System.nanoTime();
function_or_block_whose_time_i_intend_to_measure();
long tock = System.nanoTime();
Run Code Online (Sandbox Code Playgroud)

编译器是否会以我想要测量的方式在tick和tock之间不执行的方式重组代码?例如,

long tick = System.nanoTime();
long tock = System.nanoTime();
function_or_block_whose_time_i_intend_to_measure();
Run Code Online (Sandbox Code Playgroud)

如果是这样,保留执行顺序的正确方法是什么?

编辑:示例说明了用nanoTime乱序执行:

public class Foo {
    public static void main(String[] args) {
        while (true) {
            long x = 0;

            long tick = System.nanoTime();
            for (int i = 0; i < 10000; i++) { // This for block takes ~15sec on my machine
                for (int j = 0; j < 600000; j++) {
                    x = x + x * x;
                }
            }

            long tock = System.nanoTime();
            System.out.println("time=" + (tock - tick));
            x = 0;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面代码的输出:

time=3185600
time=16176066510
time=16072426522
time=16297989268
time=16063363358
time=16101897865
time=16133391254
time=16170513289
time=16249963612
time=16263027561
time=16239506975
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,第一次迭代中测量的时间明显低于后续运行中的测量时间。我认为这是由于乱序执行所致。我第一次迭代做错了什么?

Dee*_*ala 0

编译器是否会以我打算测量的方式重新组织代码,而不是在tick和tock之间执行?

没有。那永远不会发生。如果编译器优化出现问题,那将是一个非常严重的错误。引用维基百科的一句话。

运行时(在这种情况下,通常指动态编译器、处理器和内存子系统)可以自由地引入任何有用的执行优化,只要保证隔离线程的结果与其完全相同。如果所有语句都按照语句在程序中出现的顺序(也称为程序顺序)执行。

所以只要结果与按程序顺序执行时相同,就可以进行优化。在您引用的情况下,我会假设优化是本地的,并且没有其他线程对此数据感兴趣。进行这些优化是为了减少成本高昂的主内存访问次数。仅当涉及多个线程并且它们需要知道彼此的状态时,您才会遇到这些优化的麻烦。

现在,如果两个线程需要一致地查看彼此的状态,它们可以使用易失性变量或内存屏障(同步)来强制对主内存的写入/读取进行序列化。Infoq 就此发表了一篇不错的文章,您可能会感兴趣。