x86架构上的Java,易失性和内存障碍

kRs*_*kRs 5 java multithreading volatile memory-barriers

这更像是一个理论问题.我不确定所有的概念,编译器行为等是否都是最新的并且仍然在使用,但我想确认我是否正确理解了我正在努力学习的一些概念.

语言是Java.

从我到目前为止所理解的,在X86架构上,StoreLoad障碍(尽管用于实现它们的确切的CPU指令)是在Volatile写入之后放置的,以使其在其他线程中的后续易失性读取中可见(因为x86不保证较新的读取总是看到较旧的写入)(参考http://shipilev.net/blog/2014/on-the-fence-with-dependencies/)

现在从这里(http://jpbempel.blogspot.it/2013/05/volatile-and-memory-barriers.html)我看到:

public class TestJIT
{
    private volatile static int field1;
    private static int field2;
    private static int field3;
    private static int field4;
    private static int field5;
    private volatile static int field6;

    private static void assign(int i)
    {
        field1 = i << 1; // volatile
        field2 = i << 2;
        field3 = i << 3;
        field4 = i << 4;
        field5 = i << 5;
        field6 = i << 6; // volatile.
    }

    public static void main(String[] args) throws Exception
    {
        for (int i = 0; i < 10000; i++)
        {
            assign(i);
        }
        Thread.sleep(1000);
    }
}
Run Code Online (Sandbox Code Playgroud)

生成的程序集仅在field6赋值后才具有StoreLoad,而不是在field1赋值之后,但是它也是volatile.

我的问题:

1)到目前为止我写的是否有意义?还是我完全曲解了什么?

2)为什么编译器在field1 volatile赋值后省略了StoreLoad?这是优化吗?但它有一些缺点吗?例如,在field1赋值后踢入的另一个线程,即使它已被实际更改,仍可能读取field1的旧值?

Dim*_*rov 5

1)到目前为止我写的东西有意义吗?还是我完全误解了什么?

我认为你做对了一切。

2) 为什么编译器在 field1 volatile 赋值后会忽略 StoreLoad?这是优化吗?但它有一些缺点吗?

是的,这是一种优化,但要做到正确是一个非常棘手的问题。

Doug Lea的JMM食谱实际显示的两个连续的情况下,所推荐的障碍的实例volatile存储和有StoreLoad年代后它们中的每一个有一个StoreStore的两个店和一之间(86无操作)StoreLoad只有在第二个。然而,Cookbook 指出,相关分析可以相当参与。

编译器应该能够证明volatile在 write tofield1和 write to之间的同步顺序中不会发生读取field6。我不确定这是否可行(通过当前的 HotSpot JIT)如果TestJIT稍微改变volatile一下,以便同时在另一个线程中执行相当数量的加载。

例如,另一个线程在 field1 赋值后启动,即使它实际上已被更改,它是否仍可能读取 field1 的旧值?

如果volatile加载按照volatile同步顺序跟随存储,则不应允许发生这种情况。所以如上所述,我认为 JIT 可以逃脱它,因为它没有看到任何volatile负载正在完成。

更新

更改了 JMM Cookbook 示例的详细信息,因为kRs指出我将 a 误认为StoreStore是StoreLoad. 答案的本质根本没有改变。


Pet*_*rey 0

为什么编译器在 field1 易失性赋值后省略 StoreLoad?

仅要求第一次加载和最后一次存储是易失性的。

这是一种优化吗?

如果发生这种情况,这是最有可能的原因。

但它有一些缺点吗?

只不过你靠的是有两家店的一个屏障。即您需要field1先查看更改field6,而不是偶然发生的变化。

即使 field1 实际上已更改,仍可能读取它的旧值吗?

是的,尽管您无法确定是否发生了这种情况,但您是否希望看到新值,即使其他字段可能尚未设置。