java 并发代码中赋值运算符的返回值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12850676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Return value of assignment operator in concurrent code
提问by BeeOnRope
Given the following class:
鉴于以下类:
class?Foo?{
public?volatile?int?number;
public?int?method1()?{
int?ret?=?number?=?1;
return?ret;
}
public?int?method2()?{
int?ret?=?number?=?2;
return?ret;
}
}
and given multiple threads calling method1()
and method2()
concurrently on the same Foo
instance, can a call to method1() ever return anything other than 1?
并且给定多个线程在同一个实例上同时调用method1()
和method2()
并发Foo
,对 method1() 的调用能返回 1 以外的任何值吗?
采纳答案by Bringer128
The JLS 15.26 specifies:
JLS 15.26 规定:
There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.
有 12 个赋值运算符;所有的语法都是右关联的(它们从右到左分组)。因此,a=b=c 表示 a=(b=c),即先将 c 的值赋给 b,然后再将 b 的值赋给 a。
Ted Hopp's answer shows that Sun's javac doesn't follow this behaviour, possibly as an optimisation.
Ted Hopp 的回答表明 Sun 的 javac 没有遵循这种行为,这可能是一种优化。
Due to the threading here, the behaviour of method1 would be undefined. If Sun's compiler makes the behaviour constant then it doesn't break from the undefined behaviour.
由于这里的线程,method1 的行为将是未定义的。如果 Sun 的编译器使行为保持不变,那么它就不会脱离未定义的行为。
回答by Ted Hopp
I think the answer depends on the compiler. The language specifies:
我认为答案取决于编译器。语言规定:
At run-time, the result of the assignment expression is the value of the variable after the assignment has occurred.
在运行时,赋值表达式的结果是赋值发生后变量的值。
I suppose that theoretically the value could be changed before the second (leftmost) assignment occurs.
我想理论上该值可以在第二个(最左边的)分配发生之前改变。
However, with Sun's javac compiler, method1
will will turn into:
但是,用 Sun 的 javac 编译器,method1
会变成:
0: aload_0
1: iconst_1
2: dup_x1
3: putfield #2; //Field number:I
6: istore_1
7: iload_1
8: ireturn
This duplicates the constant 1
on the stack and loads it into number
and then into ret
before returning ret
. In this case, it won't matter if the value stored in number
is modified before assignment to ret
, because 1
, not number
is being assigned.
这会复制1
堆栈上的常量并将其加载到number
然后ret
在返回之前加载ret
。在这种情况下,number
在分配给 之前是否修改了存储的值并不重要ret
,因为1
, notnumber
正在被分配。
回答by irreputable
Either the statement contains a volatile read, or it doesn't contain a volatile read. There cannot be any ambiguity here, since volatile read is very important to program semantics.
该语句要么包含易失性读取,要么不包含易失性读取。这里不能有任何歧义,因为易失性读取对程序语义非常重要。
If javac can be trusted, we can conclude that the statement doesn't involve a volatile read of number
. The value of an assignment expression x=y
is really just the value of y
(after conversions).
如果可以信任 javac,我们可以得出结论,该语句不涉及number
. 赋值表达式x=y
的值实际上只是y
(转换后)的值。
We can also deduce that
我们还可以推断出
System.out.println(number=1);
does not involve reading number
不涉及阅读 number
String s;
(s="hello").length();
does not involve reading s
不涉及阅读 s
x_1=x_2=...x_n=v
does not involve reading x_n, x_n-1, ...
; instead, the value of v
is directly assigned to x_i
(after necessary conversions through types of x_n, ... x_i
不涉及阅读x_n, x_n-1, ...
;相反, 的值v
直接分配给x_i
(通过类型的必要转换后x_n, ... x_i