数组值的线程可见性更改

时间:2015-02-11 15:05:33

标签: java multithreading

假设我有以下课程:

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是否保证获得值1,因为最终和发生在之前的关系,即使数组中的值设置在此之外也是如此?

编辑:在第二个示例中,数组永远不会更改,因此名称为“ImmutableArray”

第二次编辑:

所以我对答案的理解是:鉴于此:

int a = 0
volatile int b = 0;

如果线程A执行以下操作:

a = 1;
b = 1;

然后线程B执行以下操作:

a == 1; // true
b == 1; // true

如此不稳定是一种障碍,但障碍在什么时候结束并允许再次重新排序指令?

2 个答案:

答案 0 :(得分:2)

两种情况都是正确的。事实上,即使你放松了问题陈述,你也是对的。

在第一个例子中,无论后来的线程B评估get(1)多少,都不能保证它会观察线程A对set(1, 100)的调用所写的值。

在第二个示例中,final上的ints volatile上的 arr将是足以让你有保证观察ints[0] = 5。如果没有volatile,您将无法保证观察ImmutableArray实例本身,但无论何时观察它,您都可以保证在完全构建状态下观察它。更具体地说,保证涉及从构造函数返回时对象的final字段可到达的完整状态。

答案 1 :(得分:1)

  

我的理解是,无法保证线程B会看到线程A [制作]

的更改

正确。

  

线程B是否保证获得值1,因为最终和发生在之前的关系?

没有。当您声明volatile ImmutableArray arr;时,唯一变为volatile的是对arr的引用,而不是arrarr.ints)的内容,也不是arr内容的内容1}}(arr.ints[0])。