java - 不稳定的保证和乱序执行

标签 java volatile java-memory-model

重要编辑我知道“发生在之前”在两个任务发生的线程中我的问题是 另一个 em> 线程正在读取“b”非空,而“a”仍为空。所以我知道,如果您从与之前调用 setBothNonNull(...) 的线程相同的线程中调用 doIt(),那么它不会抛出 NullPointerException。但是,如果一个调用 doIt() 从另一个线程 而不是调用 setBothNonNull(...) 呢?

请注意,此问题仅与 volatile 关键字有关,而 volatile 保证:它不是synchronized 关键字(所以请不要回答“你必须使用同步”,因为我没有任何问题要解决:我只是想了解关于 out 的 volatile 保证(或缺乏保证)顺序执行)。

假设我们有一个包含两个 volatile 字符串引用的对象,这些引用被构造函数初始化为 null,并且我们只有一种方法来修改这两个字符串:通过调用 setBoth(.. .) 并且我们只能在之后将它们的引用设置为非空引用(仅允许构造函数将它们设置为空)。

例如(这只是一个例子,还没有问题):

public class SO {

    private volatile String a;
    private volatile String b;

    public SO() {
        a = null;
        b = null;
    }

    public void setBothNonNull( @NotNull final String one, @NotNull final String two ) {
        a = one;
        b = two;
    }

    public String getA() {
        return a;
    }

    public String getB() {
        return b;
    }

}

setBothNoNull(...)中,分配非空参数“a”的行出现在分配非空参数“b”的行之前。

那么如果我这样做(再一次,没有问题,问题来了):

doIt() {
    if ( so.getB() != null ) {
        System.out.println( so.getA().length );
    }
}

我的理解是否正确,即由于乱序执行我会得到 NullPointerException

换句话说:不能保证因为我读到了一个非空的“b”,我就会读到一个非空的“a”?

由于无序(多)处理器和 volatile 的工作方式“b”可以在“a”之前分配?

volatile 保证在写入之后的读取将始终看到最后写入的值,但是这里有一个无序的“问题”对吗? (再一次,“问题”是故意试图理解 volatile 关键字和 Java 内存模型的语义,而不是解决问题。

最佳答案

不,您永远不会获得 NPE。这是因为 volatile 还具有引入happens-before 关系的内存效应。换句话说,它将防止重新排序

a = one;
b = two;

上面的语句,不会被重新排序,如果 b 已经有值 两个

David Holmes 对此进行了解释:
http://markmail.org/message/j7omtqqh6ypwshfv#query:+page:1+mid:34dnnukruu23ywzy+state:results

编辑(响应后续): Holmes 的意思是,如果只有线程 A,编译器理论上可以进行重新排序。但是,还有其他线程,它们可以检测到重新排序。这就是为什么不允许编译器进行重新排序的原因。 Java 内存模型需要编译器专门确保没有线程会检测到这种重新排序。

But what if one is calling doIt() from another thread than the one calling setBothNonNull(...) ?

不,你永远不会有 NPE。 volatile 语义确实强加了线程间的顺序。这意味着,对于所有现有线程,one 的分配发生在 two 的分配之前。

关于java - 不稳定的保证和乱序执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2441279/

相关文章:

java - springboot-rsocket如何接收多个参数?

scala - 我的 Scala Actor 的属性是否应该标记为@volatile?

java - Java中 "volatile"是什么意思?

multithreading - 我如何理解读取内存障碍和 volatile

java - 对象是从 Java 中的引用数组中预取的吗?

java - 为什么 volatile 变量比普通同步更有效

java - 抽象类为 parcelable

java - Drools Execution,获取撤回数量

java - 什么是 NullPointerException,我该如何解决?

java - volatile 是否同步原子数据类型的数组?