Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Volatile引用,然后设置变量的值_Java - Fatal编程技术网

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可以重新排序,同时;,它可能会得到实例变量value的默认值,即0。或者您是否假设线程2将在线程1执行之后的很长时间内执行代码段。@ShirgillFarhanAnsari-否。这是jdk 5+内存模型中volatile的保证之一。内存模型更改包括非易失性更改,这是由volatile创建的before关系的一部分。这就是为什么volatile与jdk5+世界中的synchronized具有相同的内存效果。换句话说,第一个非易失性赋值(在
集合(3)
中)不能在
m
的易失性赋值之后重新排序。令人印象深刻的是,我猜您的意思是-当线程A写入易失性变量,然后线程B读取相同的变量时,在写入易失性变量之前对A可见的所有变量的值在读取易失性变量后对B可见。因此,从内存可见性的角度来看,写入一个易失性变量就像退出一个同步块,而读取一个易失性变量就像进入一个同步块。@ShirgillFarhanAnsari-这几乎完全正确。