Java中与Thread.MemoryBarrier相等的方法

3
在Java中,我该如何显式触发完整的内存屏障/栅栏,与调用```java.util.concurrent.locks.LockSupport.parkNanos(1)```等效?
System.Threading.Thread.MemoryBarrier();

在C#中怎么实现?

我知道自从Java 5版本以来,对volatile变量的读写会导致完整的内存屏障,但也许有一种(高效)的方法可以不用volatile实现。


在同一对象上进行同步或者从相同的volatile字段中读取。 - Sotirios Delimanolis
3个回答

3
MemoryBarrier()相比,Java的是一个更加锋利的工具,在保持线程安全的同时留下了更多的激进优化余地。
正如你所期望的那样,更锋利的工具也需要更多的谨慎使用,这就是volatile变量访问语义的描述方式。您必须在写入站点上写入volatile变量,并在每个读取站点上从同一volatile中读取。由此可以推出,您可以拥有任意数量的独立的本地化"内存屏障",每个volatile变量一个,每个屏障只保护可从该变量到达的状态。
通常称为"safe publication"(虽然这是一个更普遍的术语),并意味着填充一个不可变对象图,该对象图将在线程之间共享,然后将对其的引用写入volatile变量。

当在写入端使用MemoryBarrier时,读取端可能会重新排序,因此在C#中,在读取端也需要调用MemoryBarrier。因此,在Java中,与MemoryBarrier等效的代码将是以下代码吗?或者由于优化而无法工作?public class Helper { private static volatile int a = 0; public static void MemoryBarrier() { int b = a; a = 0; } } - ominug
是的,我认为这可以被视为等效的(不允许优化掉volatile读或写);但是,最好将其拆分为读取和写入屏障。而且,最重要的是,您最好编写符合惯用法的Java代码,而不是您提出的辅助类。 - Marko Topolnik

2

Java 8 通过 JEP 108 引入了另一种可能性。Java API 中增加了三个屏障的访问,分别是fullFence、loadFence和storeFence。


0

没有直接的等价物。使用volatile字段或更高级的东西。


那么我应该在Java中编写自己的帮助类吗?public class Helper { private static volatile int a = 0; public static void MemoryBarrier() { int b = a; } } - ominug
可以这样做,但这不是一个好主意,因为您将在低级别上工作。最好使用高级别的东西来为您完成这项工作。我试图通过示例来解释。您可以使用内存屏障来确保变量(或多个变量)的写入和读取之间的可见性。但更好的方法是直接在变量声明中手动放置volatile,并让Java为您完成,这样可以消除样板代码,并且还可以帮助您在添加新的变量访问时不会忘记放置屏障到您的代码中。 - talex
有什么问题吗?请查看我的其他评论 - ominug
1
@ominug 另一个没问题。你可以简化它为 a=a; - talex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接