Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.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_Memory Barriers_Memory Model_Java Memory Model - Fatal编程技术网

Java中使用的内存围栏是什么?

Java中使用的内存围栏是什么?,java,concurrency,memory-barriers,memory-model,java-memory-model,Java,Concurrency,Memory Barriers,Memory Model,Java Memory Model,在试图理解如何实现SubmissionPublisher(|),在版本9中添加到Java SE的一个新类时,我偶然发现了一些API调用,我以前不知道: fullFence,acquiredfence,releaseffence,loadfence和storefence 在做了一些研究之后,特别是关于记忆障碍/围栏的概念(我以前听说过,是的;但从未使用过它们,因此对它们的语义非常不熟悉),我想我已经基本了解了它们的用途。尽管如此,由于我的问题可能来自一种误解,我想首先确保我的回答是正确的: 内存障

在试图理解如何实现
SubmissionPublisher
(|),在版本9中添加到Java SE的一个新类时,我偶然发现了一些API调用,我以前不知道:

fullFence
acquiredfence
releaseffence
loadfence
storefence

在做了一些研究之后,特别是关于记忆障碍/围栏的概念(我以前听说过,是的;但从未使用过它们,因此对它们的语义非常不熟悉),我想我已经基本了解了它们的用途。尽管如此,由于我的问题可能来自一种误解,我想首先确保我的回答是正确的:

  • 内存障碍是关于读写操作的重新排序约束

  • 内存障碍可以分为两大类:单向和双向内存障碍,这取决于它们是对读还是写设置约束,还是同时对读和写设置约束

  • 但是,这些与
    VarHandle
    提供的不匹配<但是,在代码> Val句柄< /Cord>中,内存屏障的一些提供了与它们相应的C++内存屏障兼容的排序效果。>/P>
    • #fullFence
      原子线程围栏(内存顺序顺序顺序cst)兼容
    • #acquireFence
      原子线程(内存(顺序)获取)围栏兼容
    • #releaseffence
      原子线程(内存(顺序)释放)围栏兼容
    • C++ >加载程序>代码> >代码>存储库> /COD>没有兼容的C++计数器部分
  • compatible这个词在这里似乎非常重要,因为当涉及到细节时,语义明显不同。例如,所有C++障碍都是双向的,而java的障碍并不一定(必须)。
  • 这些特别取决于所使用的屏障类型和以前在其他线程中执行的屏障指令。由于barrier指令的全部含义是特定于硬件的,因此我将坚持使用更高级别(C++)的barrier。例如,在C++中,执行释放屏障指令之前的更改对于执行捕获障碍指令的线程是可见的。李> 我的假设正确吗?如果是,我的问题是:

  • VarHandle
    中可用的内存屏障是否会导致任何类型的内存同步

  • 无论它们是否会导致内存同步,在Java中,重新排序约束对什么有用?当涉及易失性字段、锁或
    VarHandle
    操作(如
    #compareAndSet
    )时,Java内存模型已经为排序提供了一些非常有力的保证


  • 如果您正在寻找一个示例:
    BufferedSubscription
    ,SubmissionPublisher(上面链接的源代码)的一个内部类,在第1079行建立了一个完整的围栏(函数
    growtandadd
    ;因为链接的网站不支持片段标识符,所以只支持CTRL+F)。然而,我不清楚它的用途。

    这主要是一个没有答案的答案,真的(最初想把它作为一个评论,但正如你所看到的,它太长了)。只是我自己对此提出了很多疑问,做了很多阅读和研究,在这个时候我可以放心地说:这很复杂。我甚至用编写了多个测试来了解它们是如何工作的(同时查看生成的汇编代码),虽然其中一些测试在某种程度上是有意义的,但总体来说,这个主题并不容易

    您首先需要了解的是:

    Java语言规范(JLS)在任何地方都没有提到障碍。对于java来说,这将是一个实现细节:它实际上是在语义之前发生的。为了能够根据JMM(Java内存模型)正确地指定它们

    这是正在进行的工作

    第二,如果你真的想从这里开始。这次谈话令人难以置信。我最喜欢的部分是赫伯·萨特举起他的5个手指说:“这就是有多少人能够真正正确地使用这些工具。”这应该会让你了解其中的复杂性。尽管如此,还是有一些简单的例子很容易理解(比如由多个线程更新的计数器,它不关心其他内存保证,只关心它本身是否正确递增)

    另一个例子是(在java中)需要一个
    volatile
    标志来控制线程的停止/启动。你知道,古典的:

    volatile boolean stop = false; // on thread writes, one thread reads this    
    
    如果您使用java,您就会知道,如果没有
    volatile
    ,这段代码就会被破坏(例如,您可以阅读为什么没有它就会破坏双重检查锁定)。但是您是否也知道,对于一些编写高性能代码的人来说,这太过分了
    volatile
    read/write也有保证——这有一些很强的保证,有些人想要一个较弱的版本

    线程安全标志,但不是易失性标志?是的,完全正确:
    VarHandle::set/getOpaque

    你会问为什么有人会需要它,比如说?并非所有人都对
    volatile
    支持的所有更改感兴趣

    让我们看看如何在java中实现这一点。首先,API中已经存在这样的奇异事物:
    AtomicInteger::lazySet
    。这在Java内存模型和中未指定;仍然有人使用它(LMAX、afaik或)。我想,
    AtomicInteger::lazySet
    VarHandle::releaseffence
    (或者
    VarHandle::storefence


    让我们试着回答为什么有人需要这些

    JMM基本上有两种访问字段的方法:普通和易失性(这保证了顺序一致性)。