- 写final域的重排序规则
- 读final域的重排序规则
- final域是引用类型
- 为什么final引用不能从构造函数内”溢出”
- final语义在处理器中的实现
- JSR-133为什么要增强final的语义
- 参考
与前面介绍的锁和volatile
相比较,对final
域的读和写更像是普通的变量访问。对于final
域,编译器和处理器要遵守两个重排序规则。
- 在构造函数内对一个
final
域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。 - 初次读一个包含
final
域的对象的引用,与随后初次读这个final
域,这两个操作之间不能重排序。
下面,我们通过一些示例性的代码来分别说明这两个规则。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class FinalExample {
int i; //普通变量
final int j; //final变量
static FinalExample obj;
public void FinalExample () { //构造函数
i = 1; //写普通域
j = 2; //写final域
}
public static void writer () { //写线程A执行
obj = new FinalExample ();
}
public static void reader () { //读线程B执行
FinalExample object = obj; //读对象引用
int a = object.i; //读普通域
int b = object.j; //读final域
}
}
这里假设一个线程A执行writer()
,随后另一个线程B执行reader()
。下面我们通过这两个线程的交互来说明这两个规则。