7、final域

final域

final域重排序规则

对于final域,编译器和处理器要遵守两个重排序规则:
1、在构造函数对final域的写入,与随后把这个构造的对象的引用赋值给一个引用变量,这两个操作不能重排序。
2、初次读final域的对象的引用,与随后初次读final域,这两个操作不能重排序。

public 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 ()方法。

对于final域,编译器和处理器要遵守两个重排序规则:
1、在构造函数对final域的写入,与随后把这个构造的对象的引用赋值给一个引用变量,这两个操作不能重排序。
2、初次读final域的对象的引用,与随后初次读final域,这两个操作不能重排序。

写final域的重排序规则
写final域的重排序规则禁止把final域的写重排序到构造函数之外。这个规则的实现包含下面2个方面:
1、JMM禁止编译器把final域的写重排序到构造函数之外。
2、编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障。这个屏障禁止处理器把final域的写重排序到构造函数之外。

读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读包含这个final域的对象的引用。在这个示例程序中,如果该引用不为null,那么引用对象的final域一定已经被A线程初始化过了。

总结:

为什么final域有这样的语义呢?如果在多线程开发中对一个final变量的读。比如,一个线程当前看到一个整形final域的值为0(还未初始化之前的默认值),过一段时间之后这个线程再去读这个final域的值时,却发现值变为了1(被某个线程初始化之后的值)。

final域对于编译器和处理器来说有两个重排序规则:

  1. 写: final域写入和对象引用赋值这两个操作不能重排序 – 保证创建的顺序性
  2. 读: 初次读对象的引用和里面的final域不能重排序 – 保证读的顺序性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值