final可以用来修饰类、方法、变量,分别有不同的意义。

修饰类:这个类不能被继承,所有的方法不能被重写,但是里面的成员变量并不是不可变得,如果需要让它们不可变则需要用final去修饰变量。

修饰方法:不可以被重写,但是子类可以去使用这个方法。

修饰变量:不可修改,可以用于保护只读数据,尤其是在并发中,有利于减少额外的同步开销,也可以省去一些防御性的拷贝。

final指的是引用不可变性,也就是说他只能指向初始化的那个对象,而不关心指向对象内容的变化。所以被final修饰的变量必须被初始化。

 

关于private和final关键字还有一点联系,这就是类中所有的private方法都隐式地指定为是final的,由于无法在类外使用private方法,所以也就无法覆盖它。

 

除了volatile修饰变量可以禁止指令重排序外,final也可以禁止指令重排序

final域的内存定义,

相比于锁与volatile相比,对final域的读和写更像是普通的变量访问

对于final域来说,编译器与处理器要遵守两个重排序规则

    1、在构造函数内对一个final域的写入,与随后把这个被构造对象的引用复制给一个引用变量,这两个操作之间不能重排序。

JMM禁止编译器将final域的写重排序到构造函数之外,

编译器会在final域的写之后,构造函数的return之前会加入一个StoreStore屏障,

这样可以确保在对象引用被任何一个线程可见之前,对象的final域已经被正确初始化过了,如果没有被final修饰的普通变量,会在读线程看到对象引用时,对象还未构造完成。

 

     2、初次读一个包含final域的对象引用与随后初次读这个final域,这两个操作之间不能重排序。

在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作,编译器会在读final域的操作之前插入一个LoadLoad屏障。

这样会让读final域的重排序规则会将对象的final域操作限定在读对象引用之后。保证了在读一个对象的final域之前,一定会读包含这个final域对象的引用。如果是未被final修饰的普通变量,读对象的普通域的操作会被处理器重排序在读对象引用之前。

 

保证了final引用不能从构造函数中溢出,在构造函数内部,不能让这个被构造对象的引用被其他的线程课件,也即是对象的引用不能再构造函数中溢出。

在构造函数返回前,被构造对象的引用不能为其它线程所见,因为此时的final域还未被初始化,早构造函数返回后,任意线程都可以看到final域正确初始化后的值。