Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 装载屏障真正的作用是什么?_Java_Concurrency_Volatile - Fatal编程技术网

Java 装载屏障真正的作用是什么?

Java 装载屏障真正的作用是什么?,java,concurrency,volatile,Java,Concurrency,Volatile,在Java中,当两个线程共享以下变量时: int a; volatile int b; 如果线程1执行以下操作: a = 5; b = 6; 然后在这两条指令之间插入StoreStore屏障,“a”被刷新回主内存 现在,如果线程2执行以下操作: if(b == 6) a++; 在两者之间插入荷载屏障,我们保证,如果“b”的新值可见,则“a”的新值也可见。但这究竟是如何实现的呢?LoadLoad是否使CPU缓存/寄存器失效?或者只是指示CPU获取变量的值,然后再从CPU读取volatile

在Java中,当两个线程共享以下变量时:

int a;
volatile int b;
如果线程1执行以下操作:

a = 5;
b = 6;
然后在这两条指令之间插入StoreStore屏障,“a”被刷新回主内存

现在,如果线程2执行以下操作:

if(b == 6)
 a++;
在两者之间插入荷载屏障,我们保证,如果“b”的新值可见,则“a”的新值也可见。但这究竟是如何实现的呢?LoadLoad是否使CPU缓存/寄存器失效?或者只是指示CPU获取变量的值,然后再从CPU读取volatile

我找到了有关Load barrier()的以下信息:

装载障碍物的顺序为:装载1;载荷;Load2确保 Load1的数据在Load2和all访问数据之前加载 随后加载指令。通常,显式加载 在执行推测性加载的处理器上需要屏障 和/或无序处理,其中等待加载指令可以 绕过等待的商店。在保证始终保持 按照负载顺序,屏障相当于无操作


但它并没有真正解释这是如何实现的。

我将举一个例子说明这是如何实现的。你可以阅读更多的细节。对于x86处理器,正如您所指出的,LoadLoad最终将成为no-ops。我在文章中指出,马克

Doug列出了StoreStore、LoadLoad和LoadStore

因此,本质上唯一需要的障碍是x86体系结构的StoreLoad。那么,这是如何在低水平上实现的呢

这是该博客的摘录:

以下是它为易失性和非易失性读取生成的代码:

nop                       ;*synchronization entry
mov    0x10(%rsi),%rax    ;*getfield x
xchg   %ax,%ax
movq   $0xab,0x10(%rbx)
lock addl $0x0,(%rsp)     ;*putfield x
对于易失性写入:

nop                       ;*synchronization entry
mov    0x10(%rsi),%rax    ;*getfield x
xchg   %ax,%ax
movq   $0xab,0x10(%rbx)
lock addl $0x0,(%rsp)     ;*putfield x
lock
指令是Doug的食谱中列出的存储负载。但是,lock指令也会将所有读取与其他进程同步

锁定指令可用于同步一个用户写入的数据 并由另一个处理器读取

这减少了为易失性负载发出负载存储屏障的开销

尽管如此,我将重申亚西尔亚斯所指出的。它发生的方式对开发人员来说并不重要(如果您对处理器/编译器实现者感兴趣,那就另当别论了)。
volatile
关键字是一种界面语句

  • 您将获得由另一个线程写入的最新读取
  • 您不会被JIT编译器优化烧坏
  • 如果该加载的计算结果为no op,那么线程2可以继续使用缓存的值

    烹饪手册中的“可订购”表涵盖了这一点

    编程顺序为

    read b
    read a
    write a
    
    “缓存”是指代码被重新排序

    read a
    ...
    read b
    

    这种重新排序是禁止的。

    答案取决于处理器体系结构-同一文档中的每个处理器指令都有一个表,该表显示,例如,
    LoadLoad
    在x86上是不可操作的。那么它是如何工作的呢?我的意思是,在StoreStore之后,这些值被刷新回内存。但是线程2应该如何看到它们呢?如果该加载的计算结果为no op,那么线程2可以继续使用缓存的值。因为处理器的内存模型足够强大,它可以保证情况会如此。我想说的是,Java承诺,如果您使用volatile,某些事情将/不会发生。如何在JVM中实现这一点是特定于处理器的,并使用特殊指令(如果相关,则不使用指令)。您可以在这里阅读关于LoadLoad/x86点的更多信息:您可以进一步阅读LoadLoad不是no-op的CPU体系结构,例如ARM。似乎是沉重的东西,虽然:)不错的链接。我会愚蠢地重新表述:“您将获得由另一个线程写入的最新读取”=>“您最终将在随后读取volatile变量时看到写入—“最终”意味着在实践中几乎立即”;-)实际上,如果您对应用程序运行最快的硬件或如何实现最高性能感兴趣,这一点很重要。我们希望从使用四插槽Xeon(64 SMT)中获得比最终更多的好处。如果您无法控制硬件或仅在单个套接字上运行,这可能不是问题,但并发实现细节以及它们如何影响大型计算机上的可伸缩性,如果在早期就知道它们,肯定会影响设计。@RalfH我是代表普通开发人员使用
    volatile
    关键字说话的。一般来说,开发人员不需要担心实现的易变性。当知道底层架构改变了您将如何使用volatile时,您是否看到过一个实例?:)没有,因为我也不知道硬件是如何实现的,所以我宁愿进行分析。这就是为什么我注意到ConcurrentHashMap中的易失性get-like对性能不好,所以我们最终在内容稳定后用CopyOnWriteHashMaps替换它们。如果你想知道下一步会发生什么,硬件细节是很重要的。我想知道Haswell中的硬件事务性内存对于Java并发性到底意味着什么。好吧,这让人费解:)我不确定我的理解是否正确:因为x86上的加载屏障是不可操作的,所以Marc的程序生成了一个StoreLoad屏障?(这是以“lock”开头的行)。如果volatile读取生成了一个额外的指令(锁),为什么他说我们可以期望volatile读取是免费的?回到我最初的问题,如果我们在Marc的示例中添加了一个非易失性的读取,那么“锁定”指令会起到神奇的作用吗(确保非易失性的可见性)?我实际上指的是CPU缓存中的真正缓存,而不是指令的重新排序。@zhong我认为Janek的担心