考虑一下代码段:
class Mutable {
private volatile int value;
public int get()
{
return value;
}
public int set(int value)
{
this.value = value;
}
}
class Test {
public volatile Mutable m;
}
所以使用以下序列:
Thread-1: get() // returns 2
Thread-2: set(3)
Thread-1: get() // guaranteed to return 3 due to volatile with property value
但我无法理解作者的以下注释 -
但是,一个注释,当分配m时,内部值将是 正确可见。 只有在后续调用set()之后才会这样做 不写你有问题。
请举例说明。他在谈论哪个问题?
答案 0 :(得分:3)
因此,上次评论令人困惑的原因是因为它脱离了背景。您提供的示例代码与该评论所针对的original code的不同。在原始代码中,value
不是 volatile。如果value
不易变,则会出现以下情况。
线程1:
Mutable tmp = new Mutable();
tmp.set(3);
Test.m = tmp;
线程2:
Test.m.get(); // *** this is guaranteed to return 3 due to the happens before rules.
线程1:
Test.m.set(5);
线程2:
Test.m.get(); // no guaranatees here, could be 3, could be 5
我的评论指的是" ***"部分,m
的不稳定分配提供了在关系之前发生的事情,这使得" 3"对Thread2可见(由于m
的易失性读取)。 (为了重新迭代,value
在这个例子中不易变。)
答案 1 :(得分:1)
我相信,有问题的部分是volatile
保证了读写访问之前发生的关系。我们只是不知道快速写操作符会发生什么:
Thread-1: get() // returns 2
// no real happens-before on the 3 lines below:
Thread-2: set(3)
Thread-3: set(4)
Thread-4: set(5)
// now what?
Thread-1: get() // guaranteed to return 3 or 4 or 5 due to volatile with property value
一个更棘手的案例是增加一个计数器:
Thread-1: get() // returns 2
// no real happens-before on the 3 lines below. They all might increment the 2:
Thread-2: set(get()+1)
Thread-3: set(get()+1)
Thread-4: set(get()+1)
// now what?
Thread-1: get() // guaranteed to return 3 or 4 or 5 due to volatile with property value