假设我有以下类:
private final int[] ints = new int[5];
public void set(int index, int value) {
ints[index] = value;
}
public int get(int index) {
return ints[index]
}
线程A运行以下内容:
set(1, 100);
(非常)在线程B运行以下内容后不久:
get(1)
我的理解是,不能保证线程B会看到线程A所做的更改,因为更改可能仍在CPU缓存/寄存器中。。。或者可能存在指令重新排序这是正确的吗
接下来,如果我有以下类,会发生什么:
public class ImmutableArray {
public final int[] ints
public ImmutableArray(int[] ints) {
this.ints = ints
}
}
具有以下局部变量:
volatile ImmutableArray arr;
线程A运行以下操作:
int[] ints = new int[5];
int[0] = 1;
arr = new ImmutableArray(ints);
(非常)在线程B运行以下内容后不久:
int i = arr.ints[0];
线程B是否因为final和发生在关系之前而保证获得值1
,即使数组中的值设置在该值之外?
EDIT:在第二个例子中,数组从未更改,因此名称为"ImmutableArray"
第二版::
因此,我所理解的答案是,给定这个:
int a = 0
volatile int b = 0;
如果线程A执行以下操作:
a = 1;
b = 1;
然后线程B执行以下操作:
a == 1; // true
b == 1; // true
所以volatile起到了某种屏障的作用,但屏障在什么时候结束并允许重新排序指令?
你在这两方面都是正确的。事实上,即使你放松了你的问题陈述,你也是对的。
在第一个示例中,无论线程B稍后对get(1)
求值多少,都不能保证它会观察到线程A对set(1, 100)
的调用所写的值。
在第二个示例中,ints
上的final
或arr
上的volatile
就足以保证观察到ints[0] = 5
。如果没有volatile
,就不能保证观察到ImmutableArray
实例本身,但只要观察到它,就可以保证在完全构建的状态下观察到它。更具体地说,保证涉及到构造函数返回时从对象的final
字段可到达的完整状态。