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
原子线程(内存(顺序)释放)围栏兼容
VarHandle
中可用的内存屏障是否会导致任何类型的内存同步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基本上有两种访问字段的方法:普通和易失性(这保证了顺序一致性)。