文章目录
一、:final的常见基础概念
final能够修饰变量,方法和类,在日常代码中经常使用。
①final修饰变量
1、final修饰成员变量
每个类中的成员变量可以分为类变量(static修饰的变量)以及实例变量。针对这两种类型的变量赋初值的时机是不同的。
●类变量可以在声明变量的时候直接赋初始值或者在静态代码块中给类变量赋初始值。
●实例变量可以在声明变量的时候给实例变量赋初始值、在非静态初始化块中以及构造器中赋初始值。
因此使用final修饰的时候,需要注意:
●final修饰成员变量,该成员变量必须在创建对象之前进行赋值,否则编译失败。
●final修饰成员变量,固定的不是成员变量拥有的默认值,如果固定的是默认值,那么将导致被final修饰的成员变量的值永远无法修改,只能是默认值,这也不符合语法规则。
●final修饰成员变量,不能被修改,也无法利用set函数进行赋值。
2、final修饰局部变量
final局部变量由程序员进行显式初始化,如果final局部变量已经进行了初始化则后面就不能再次进行更改,如果final变量未进行初始化,可以进行赋值,当且仅有一次赋值,一旦赋值之后再次赋值就会出错。
②final修饰方法
当父类的方法被final修饰的时候,子类不能重写父类的该方法。比如在Object中,getClass()方法就是final修饰的,我们就不能重写该方法;但是hashCode()方法未被final所修饰,我们可以重写hashCode()方法。
被final修饰的方法是可以被重载的。
③final修饰类
当一个类被final修饰时,表明该类是不能被子类继承的。
二、:final在多线程的应用
①final域重排序规则
1、final域是基本类型
ⅰ、写final域
写final域的重排序规则禁止对final域的写重排序到构造函数之外,这个规则的实现主要包含了两个方面:
●JMM禁止编译器把final域的写操作重排序到构造函数之外。
●编译器会在final域写之后,构造函数return之前,插入一个storestore屏障。这个屏障可以禁止处理器把final域的写重排序到构造函数之外。
由此可见,写final域的重排序规则可以确保:在对象引用被任意线程可见之前,对象的final域已经被正确初始化过了。而普通域不具有这个保障。
ⅱ、读final域
读final域重排序规则为:在一个线程中,初次读对象引用和初次读该对象包含的final域,JMM会禁止这两个操作的重排序。(注意,这个规则仅仅是针对处理器),处理器会在读final域操作的前面插入一个LoadLoad屏障。实际上,读对象的引用和读该对象的final域存在间接依赖性,一般处理器不会重排序这两个操作。但是有一些处理器会重排序,因此,这条禁止重排序规则就是针对这些处理器而设定的。
读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读这个包含这个final域的对象的引用。
2、final域是引用类型
针对引用数据类型,final域写针对编译器和处理器重排序增加了这样的约束:在构造函数内对一个final修饰的对象的成员域的写入 与 随后在构造函数之外把这个被构造的对象的引用赋给一个引用变量,这两个操作是不能被重排序的。这里说“增加”是说在前面对final基本数据类型的重排序规则的基础上新增的。
②final的实现原理
写final域会要求编译器在final域写之后,构造函数返回前插入一个StoreStore屏障。读final域的重排序规则会要求编译器在读final域的操作前插入一个LoadLoad屏障。当然,对于不会进行某些操作的重排序的处理器,编译器也不会加入对应的屏障,否则就多此一举了。
③final引用不能从构造函数中“逸出”
final域写重排序规则可以确保我们在使用一个对象引用的时候该对象的final域已经在构造函数被初始化过了。但是这里其实是有一个前提条件的,也就是:在构造函数,不能让这个被构造的对象被其他线程可见,也就是说该对象引用不能在构造函数中“逸出”。否则仍然存在安全问题。
系列文章传送门:
JUC探险-1、初识概貌
JUC探险-2、synchronized
JUC探险-3、volatile
JUC探险-4、final
JUC探险-5、原子类
JUC探险-6、Lock & AQS
JUC探险-7、ReentrantLock
JUC探险-8、ReentrantReadWriteLock
JUC探险-9、Condition
JUC探险-10、常见工具、数据结构
JUC探险-11、ConcurrentHashMap
JUC探险-12、CopyOnWriteArrayList
JUC探险-13、ConcurrentLinkedQueue
JUC探险-14、ConcurrentSkipListMap
JUC探险-15、BlockingQueue
JUC探险-16、ThreadLocal
JUC探险-17、线程池