如何在不使用sun.msc.Unsafe的情况下触发全内存围栏



我有兴趣在不使用sun.misc.Unsafe的情况下触发一个完整的内存围栏。

下面的Java代码是否会触发一个满内存围栏?

public final class Foo {
    public void bar() {
        // Before memory fence?
        synchronized(this) {
            // After memory fence?
        }
    }
}

以下Java代码是否也触发满内存围栏?

public final class Foo {
    private final Object monitor = new Object();
    public void bar() {
        // Before memory fence?
        synchronized(monitor) {
            // After memory fence?
        }
    }
}
  • 参考:Java 8 Unsafe:xxxFence()指令
  • 参考编号:http://openjdk.java.net/jeps/171

如果您想手动触发一个完整的围栏,您需要查看VarHandle。它有各种各样的栅栏。

纯粹依靠同步区块或挥发物进行围栏行为是非常不可靠的。

例如:

int a=0
thread1:
   a=1
   synchronized(this){}
thread2:
   synchronized(this){}
   r1=a

"a"上存在数据争用,因为在线程1更新a=1之后,在释放锁之前,可以读取"a=1"。因此,没有与连接a的写入和1的读取的边缘同步。

JVM可以自由地生成所有可能和有效执行的子集,并且它可以选择只生成"a"保持为零并且永远看不到新值的执行(因为存在数据竞争)。所以没有考虑到整个围栏。

您想要实现什么。您只是想阻止"之前"one_answers"之后"操作的重新排序吗?你需要你的操作是原子的吗?

要回答"是"的问题,锁定将具有与全内存围栏相同的效果,甚至更多。它将确保您的Before和After操作不会被重新订购。它还将确保同步块中的所有写入对其他线程可见。此外,您在持有锁时完成的所有操作都将以原子方式发生。仅仅增加一个完整的围栏是不会实现的。

在java中触发完全隔离的另一种方法是写入易失性变量。

最新更新