Bee*_*ope 34 java concurrency variable-assignment jls
鉴于以下课程:
class?Foo?{
public?volatile?int?number;
public?int?method1()?{
int?ret?=?number?=?1;
return?ret;
}
public?int?method2()?{
int?ret?=?number?=?2;
return?ret;
}
}
Run Code Online (Sandbox Code Playgroud)
并且在同一个实例上调用多个线程method1()并method2()同时执行Foo,对method1()的调用是否可以返回除1以外的任何内容?
Ted*_*opp 15
我认为答案取决于编译器.该语言指定:
在运行时,赋值表达式的结果是赋值发生后变量的值.
我认为理论上可以在第二个(最左边)赋值发生之前更改该值.
但是,使用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
Run Code Online (Sandbox Code Playgroud)
这会复制1堆栈上的常量并将其加载到number然后ret返回之前ret.在这种情况下,如果number在分配之前修改了存储的值,则无关紧要ret,因为1没有number分配.
Bri*_*128 10
JLS 15.26规定:
有12个赋值运算符; 所有这些都是语法上的右关联(他们从右到左分组).因此,a = b = c表示a =(b = c),它将c的值赋给b,然后将b的值赋给a.
Ted Hopp的回答显示Sun的javac不遵循这种行为,可能是一种优化.
由于此处的线程,方法1的行为将是未定义的.如果Sun的编译器使行为保持不变,那么它不会破坏未定义的行为.
该语句包含易失性读取,或者它不包含易失性读取.这里不存在任何歧义,因为易失性读取对于编程语义非常重要.
如果javac可以信任,我们可以得出结论,该语句不涉及易失性读取number.赋值表达式x=y的值实际上只是y(转换后)的值.
我们也可以推断出这一点
System.out.println(number=1);
Run Code Online (Sandbox Code Playgroud)
不涉及阅读 number
String s;
(s="hello").length();
Run Code Online (Sandbox Code Playgroud)
不涉及阅读 s
x_1=x_2=...x_n=v
Run Code Online (Sandbox Code Playgroud)
不涉及阅读x_n, x_n-1, ...; 相反,值v直接分配给x_i(通过类型的必要转换后)x_n, ... x_i