关于java中的关键字final_深入分析Java中的final关键字

Java中被final修饰的变量与普通变量有何区别?被final修饰的变量不可更改、被final修饰的方法不可重写是怎样做到的?带着疑问我们一点点拨开云雾。

一、final的内存定义及规则

对于final关键字,编译器、处理器从读写两个角度限制了其使用规则:对于一个类的final修饰的变量,如果在定义是不指定初始值,那么在构造函数中必须进行初始化,在构造函数中进行final域的写入时,随后将构造后的对象引用赋值给另外一个引用变量,它们之间不能进行重排序的发生。

在读一个包含final关键字的对象引用和读这个引用的包含的final修饰的变量时,这两个操作间不能发生重排序。

下面通过一段代码分析一下具体场景:

public class FinalTest{

int i;

final int j;

static FinalTest obj;

public FinalTest(){

i = 10;

j = 20;

}

public static void finalWriter(){

obj = new FinalTest();

}

public static void finalRead(){

FinalTest object = obj;

int a = object.i;

int b= object.j;

System.out.println(a);

System.out.println(b);

}

}

这里先假设A线程执行finalWriter方法,B线程执行finalRead()方法,通过上述对于final的规则描述我们分析一下finalWriter方法的执行流程:构造一个FinalTest对象

将构造后的对象引用进行赋值

对于final修饰的变量进行赋值操作时的重排序规则如下:1、Java内存模型禁止将对final关键字修饰的变量进行写操作重排序到构造函数之外。

2、编译器会在写之后,构造函数return之前插入StoreStore屏障,这个屏障确保编译器不会把final变量写操作重排序到构造函数之外。

下面假定一种重排序的场景如下图所示:final域的写流程

上图的场景情况为变量i为普通变量,在进行赋值时发生了重排序(由于这时候有可能构造函数还未完成),在构造函数结束后,才进行了赋值,线程B读取到的i的值为赋值前的初始值0,而对于final修饰的变量j由于禁止重排序,在构造函数return前需要进行赋值,限定到了构造函数内,读取到的变量j为正确的值。

然后再分析一下执行finalRead()方法的流程:读引用变量Obj将其赋值给object变量。

读引用的普通变量i。

读引用的final修饰的变量j

对于final修饰的读操作重排序规则:在一个线程中首次读对象的引用和首次读该对象包含的final修饰的变量,Java内存模型禁止重排序(也就是说在读取一个final修饰的变量前,一定是先获取该变量对应的引用),主要原理就是在读取final修饰的变量前插入LoadLoad屏障。

假设上述情况,线程A正常执行,变量i没有发生重排序的情况,而对于线程B读取变量i和读对象的引用发生了重排序,如下图所示

读对象的普通变量i时处理器发生了重排序,读变量在读对象的引用之前发生,这时候变量还未开始进行赋值,而对于final修饰的变量j来说,由于其遵循重排序规则(读变量首先要读变量对应的对象引用),所以读取的值是正确的。

除了上述两种场景之外,假设在构造函数内使用this关键字将当前对象赋值给成员变量(逸出),如下代码所示:

public class FinalTest{

final int j;

static FinalTest obj;

public FinalTest(){

j = 20; //赋值final变量 obj = this; //this引用逸出 }

public static void finalWriter(){

new FinalTest();

}

public static void finalRead(){

System.out.println(obj.j);

}

}

这时候同样有两个线程,一个线程执行finalWriter,另外一个执行finaRead,也有可能会出现被final修饰的变量j没有进行赋值的情况。参考《Java并发编程的艺术》扫码关注“聊点源码”获取更多资讯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值