不稳定的保证和无序执行
重要编辑我知道在发生两个赋值的线程中的“之前发生”,我的问题是,当“a”仍然为空时,另一个线程是否有可能读取“b”非空。所以我知道,如果你从你之前调用setBothNonNull(...)的线程相同的线程调用doIt(),那么它不能抛出NullPointerException。但是,如果一个人从另一个线程调用doIt()而不是调用setBothNonNull(...)的线程呢?
请注意,这个问题完全是关于关键字和保证的:它不是关于关键字的(所以请不要回答“你必须使用synce”,因为我没有任何问题要解决:我只是想了解关于无序执行的保证(或缺乏保证)。volatile
volatile
synchronized
volatile
假设我们有一个对象,其中包含两个由构造函数初始化为 null 的 String 引用,并且我们只有一种方法可以修改这两个 String:通过调用 setBoth(...),并且我们只能在之后将它们的引用设置为非 null 引用(只允许构造函数将它们设置为 null)。volatile
例如(这只是一个例子,还没有问题):
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”?
因为由于无序(多)处理器和工作方式,“b”可以在“a”之前分配?volatile
volatile
保证写入后的读取应始终看到最后写入的值,但这里有一个无序的“问题”,对吗?(再一次,“问题”是故意试图理解关键字和Java内存模型的语义,而不是为了解决问题)。volatile