写final域时的重排序规则会使编译器在final域的写之后,构造函数return之前插入一个StoreStore屏障,那么下面这段程序的可能执行顺序中,为什么会出现写普通域i重排序到了StoreStore屏障之后呢?
public class FinalExample {
int i; // 普通变量
final int j; //final 变量
static FinalExample obj;
public 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 域
}
}
PS:个人结合《Java并发编程》一书中前面对volatile内存语义的解读,对内存屏障的理解是:内存屏障能够禁止屏障前面所有的操作与屏障后面所有的操作进行重排序,例如:StoreStore屏障禁止它前面的所有写操作与它后面的写操作进行重排序。
首先,你这段代码就有语法错误啊,无法通过编译,你定义了一个与类名称同名的void函数,应该是构造函数的吧。
其次,指令重拍是java编译器对代码进行的一种优化,如果我的猜的没错,去掉构造函数前的void后代码通过编译,javap查看字节码:
构造函数中的初始化语句的过程跟代码顺序是一致的啊,读也是一致的。
你自己用javap -c FinalExample 分析下字节码看看。
最后一点是我的理解,final貌似跟指令重排没有多大的关联吧。
StoreStore是cpu和内存重排序,编译器重排序可以重排序,final只限制这个变量本身,对其他变量不做限制,语义只限制不能出构造函数。这和volatile是不一样的