【搞定Java并发编程】第11篇:final域的内存语义

本文详细介绍了Java并发编程中final域的内存语义,包括final域的重排序规则、写与读final域的规则,以及final域为引用类型的情况,并解释了为何final引用不能在构造函数内“逸出”。通过理解这些规则,可以确保在正确构造对象后,任意线程都能看到final域初始化后的值。
摘要由CSDN通过智能技术生成

上一篇文章:锁的内存语义:https://blog.csdn.net/pcwl1206/article/details/84921447

目  录

1、final域的重排序规则

2、写final域的重排序规则

3、读final域的重排序规则

4、final域为引用类型

5、为什么final引用不能从构造函数内“逸出”?

6、final语义在处理器中的实现

7、JSR-133为什么要增强final的语义?


与前文中介绍的锁和volatile相比,对final域的读和写更像是普通的变量访问。本文主要用来介绍final域的内存语义。

1、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 ()方法。下面我们通过这两个线程的交互来说明这两个规则。


2、写final域的重排序规则

写final域的重排序规则禁止把final域的写重排序到构造函数之外。这个规则的实现包含下面2个方面:

  • JMM禁止编译器把final域的写重排序到构造函数之外。
  • 编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障。这个屏障禁止处理器把final域的写重排序到构造函数之外。

现在让我们分析writer ()方法。writer ()方法只包含一行代码:finalExample = new FinalExample ()。这行代码包含两个步骤:

  1. 构造一个FinalExample类型的对象;
  2. 把这个对象的引用赋值给引用变量obj。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值