「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。
茫茫人海千千万万,感谢这一秒你看到这里。希望我的文章对你的有所帮助!
愿你在未来的日子,保持热爱,奔赴山海!!
题记:关于
final关键字,它也是我们一个经常用的关键字,可以修饰在类上、或者修饰在变量、方法上,以此看来定义它的一些不可变性!像我们经常使用的String类中,它便是
final来修饰的类,并且它的字符数组也是被final所修饰的。但是一些final的一些细节你真的了解过吗?从这篇文章开始,带你深入了解
final的细节!
👋从内存模型中了解final
👩❤️👨 final对象是引用类型
上面我已经了解了final域对象是基本数据类型的一个重排序规则了,但是对象如果是引用类型呢?我们接着来:
当final域对象是一个引用类型,写final域的重排序规则增加了如下的约束:
在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外将被构造对象的引用赋值给引用变量之间不能重排序。 听起来还是有点难懂是吧,没事,代码看看!
注意一点:之前的写final域的重排序规则一样存在,只是对引用类型对象增加了一条规则。
代码:
package com.nz.test;
/**
* 测试final引用类型对象时的读写情况
*/
public class ReferenceFinalTest {
// 定义引用对象
final Person person;
private ReferenceFinalTest referenceFinalTest;
// 在构造函数中初始化,并进行赋值操作
public ReferenceFinalTest(){
person = new Person(); // 1. 初始化
person.setName("詹姆斯!"); // 2. 赋值
}
// 线程A进来进行写操作,实现将referenceFinalTest初始化
public void write(){
referenceFinalTest = new ReferenceFinalTest(); // 3. 初始化构造函数
}
// 线程B进来进行写操作,实现person重新赋值操作。
public void write2(){
person.setName("戴维斯"); // 4. 重新赋值操作
}
// 线程C进来进行读操作,读取当前person的值
public void read(){
if(referenceFinalTest != null) { // 5. 读取引用对象
String name = person.getName(); // 6. 读取person对象的值
}
}
}
class Person{
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
复制代码
首先,我们先画个可能发生情况的图解:
我们线程的执行顺序:A ——> B ——> C
接着我们对读写操作方法进行详解:
写final域重排序规则
从之前我们就知道,我们final域的写禁止重排序到构造方法外,因此1和3是不能发生重排序现象滴。
而对于我们新增的约束来说,在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外将被构造对象的引用赋值给引用变量之间不能重排序。即final域的引用对象的成员属性写入setName("詹姆斯")是不可以与随后将这个被构造出来的对象赋给引用变量jmmFinalTest重排序,因此2和3不能重排序。
所以我们的步骤是1-2-3。
读final域重排序规则
对于多线程情况下,JMM内存模型至少可以确保线程C在读对象person的成员属性时,先读取到了引用对象person了,可以读取到线程A对final域引用对象person的成员属性的写入。
可能此时线程B对于person的成员属性的写入暂时看不到,保证不了线程B的写入对线程C的可见性,因为可能线程B与线程C存在了线程抢占的竞争问题,此时的结果可能不同!
当然,如果想要保存可见,我们可以使用Volatile或者同步锁。
👨❤️👨 小结
我们可以根据数据类型分类:
基本数据类型:
- 写:在构造函数内对
final域写入,随后将构造函数的引用赋值给一个引用变量,操作不能重排序。即禁止final域写重排序到构造方法之外。 - 读:初次读一个包含
final域的对象的引用和随后初次写这个final域,不能重排序。
引用数据类型:
在基本数据类型上额外增加约束:
禁止在构造函数对一个final修饰的对象的成员域属性的写入与随后将这个被构造的对象的引用赋值给引用变量进行重排序。
🌸总结
相信各位看官看到这里,都对final关键字的这些小细节有了一定了解和认识吧,相信我,看完这个,面试官再问你的final的时候,它一定会叹为观止滴!毕竟,咱们抠的这么细致,一定会这场面试所加分的。
到这里,咱们学这个final,其实不只是为了面试,也是我们自己积累经验,自己总结知识,提升自我的其中一个点!我们永远不能单单满足一个点的细节抠到细致,对吧,我们还有一把东西等着我们探索和摸索中!接下来就是潜心学习一段时间,不浮躁,不气馁!
让我们也一起加油吧!本人不才,如有什么缺漏、错误的地方,也欢迎各位人才大佬评论中批评指正!当然如果这篇文章确定对你有点小小帮助的话,也请亲切可爱的人才大佬们给个点赞、收藏下吧,一键三连,非常感谢!
学到这里,今天的世界打烊了,晚安!虽然这篇文章完结了,但是我还在,永不完结。我会努力保持写文章。来日方长,何惧车遥马慢!
感谢各位看到这里!愿你韶华不负,青春无悔!




近期评论