Java Volatile引用,然后设置变量的值
考虑一下这个片段:Java Volatile引用,然后设置变量的值,java,Java,考虑一下这个片段: 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
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()之后才会执行
不要写m说明您有问题
请举例说明。他说的是哪一个问题?我相信,问题的部分在于
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
所以最后一条评论之所以令人困惑,是因为它被断章取义了。您提供的示例代码与该注释所指向的不同。在原始代码中,
value
不是易失性的。当值
不易波动时,则出现以下情况
线程1:
Mutable tmp = new Mutable();
tmp.set(3);
Test.m = tmp;
Test.m.set(5);
线程2:
Test.m.get(); // *** this is guaranteed to return 3 due to the happens before rules.
Test.m.get(); // no guaranatees here, could be 3, could be 5
线程1:
Mutable tmp = new Mutable();
tmp.set(3);
Test.m = tmp;
Test.m.set(5);
线程2:
Test.m.get(); // *** this is guaranteed to return 3 due to the happens before rules.
Test.m.get(); // no guaranatees here, could be 3, could be 5
我的评论是指“***”部分,其中
m
的volatile赋值提供了“before”关系,使得Thread2可以看到“3”(由于m
的volatile读取)。(要重新迭代,本例中,value
不是volatile)。volatile关键字意味着对于任何线程访问,该值都将保证更新。@Reza:我不是问volatile是什么。但是随后调用set()将如何导致b/w线程不一致。您是在询问其他人的代码/问题吗?什么是m
?你能给出作者正在谈论的实际代码吗,或者链接到它吗?@qxz:asure-public volatile Mutable m=new Mutable();我想说,由于value
上存在volatile
关键字,您的第一个代码片段肯定会返回5
,因为volatile保证了这一点。第二个我不确定。第一个代码片段的要点是我必须按照一定的顺序编写线程。jvm
不必这样做。这些集合可以并行进行。谢谢+1对于语句的重新排序。这个答案并没有说太多关于发生之前的关系,它只是指出了并行性的不确定性以及易失性成员不是原子的事实。@jtahlborn确实如此。这个答案提供了一些例子,当没有发生在关系之前。据我所知,这是OP所要求的。另外,这个答案并没有假装解释发生在之前的关系。难道你不认为当值不是易变的,那么语句1-tmp.set(3)代码>&2-Test.m=tmp如果线程2要执行Test.m.get();,则线程1执行的代码>可以重新排序,同时;,它可能会得到实例变量value的默认值,即0。或者您是否假设线程2将在线程1执行之后的很长时间内执行代码段。@ShirgillFarhanAnsari-否。这是jdk 5+内存模型中volatile的保证之一。内存模型更改包括非易失性更改,这是由volatile创建的before关系的一部分。这就是为什么volatile与jdk5+世界中的synchronized具有相同的内存效果。换句话说,第一个非易失性赋值(在集合(3)
中)不能在m
的易失性赋值之后重新排序。令人印象深刻的是,我猜您的意思是-当线程A写入易失性变量,然后线程B读取相同的变量时,在写入易失性变量之前对A可见的所有变量的值在读取易失性变量后对B可见。因此,从内存可见性的角度来看,写入一个易失性变量就像退出一个同步块,而读取一个易失性变量就像进入一个同步块。@ShirgillFarhanAnsari-这几乎完全正确。