final的语义
final的线程安全性
// FinalClass.java
public class FinalClass {
public final int i;
public int j;
public final DefineFinalObject defineFinalObject;
static FinalClass finalClass;
public FinalClass(){
// int x = i;
// DefineFinalObject var = defineFinalObject;
i = 4;
defineFinalObject = new DefineFinalObject();
try{
// code ... may throw exception
// i = 4;
// defineFinalObject = new DefineFinalObject();
j = 9;
// code ...
}catch (Exception e){}
}
static void writer(){
finalClass = new FinalClass();
System.out.println("have init FinalClass");
}
static void reader(){
if (finalClass != null){
int x = finalClass.i;
int y = finalClass.j;
System.out.printf("get x = %d, and y = %d", x, y);
}
}
public static void main(String[] args) {
FinalClass finalClass = new FinalClass();
System.out.println(finalClass.defineFinalObject);
finalClass.defineFinalObject.setAge(10);
System.out.println(finalClass.defineFinalObject);
}
}
i=4
进行写操作,会出现编译报错,对于没有使用final修饰的变量j进行写操作的j=9
则没有出现编译报错i=4
执行的写操作之前,编译器不允许对final修饰的基本/引用变量进行读操作,否则编译报错i=4
以及defineFinalObject = new DefineFinalObject()
创建对象并引用对应的对象地址defineFinalObject = new DefineFinalObject()
的方式重新指向一个新的引用地址final与static使用分析
// FinalSharedClass.java
public class FinalSharedClass {
public final static int num;
public static int x;
public final static DefineFinalObject defineFinalObject;
static {
// 静态代码块,保证在加载类信息的时候也完成上述静态数据变量的初始化赋值的操作
num = 10;
defineFinalObject = new DefineFinalObject();
System.out.printf("have finished static code for num=%d and obj=%s...\n", num, defineFinalObject);
}
{
// 默认代码块,等同于对象构造器,编译器报错,要么是声明被分配过要么是上述定义的static报没有被分配
// num = 10;
// defineFinalObject = new DefineFinalObject();
}
static void writer(){
// final 修饰的无法修改,将会编译报错提示已经分配值操作
// num = 20;
// defineFinalObject = new DefineFinalObject();
x = 10;
defineFinalObject.setAge(10);
}
static void reader(){
// must be same with the end of static code
System.out.printf("read final static num: %d \n", num);
System.out.printf("read final static defineFinalObject: %s \n", defineFinalObject);
// may be 0 or 10
System.out.printf("read static x: %d \n", x);
}
}
final的遵循的规则
i=4
优先于finalClass = new FinalClass();
,也就是两个操作不能重排序,final修饰的为引用类型也是一样遵循这个规则i 为默认值 0
的操作优先于其他线程对i 为 4
的读操作,也就是两者不能重排序,同理final修饰的引用变量也是遵循这个规则final的语义是如何实现的
// A more convenient access to dmb for our purposes
enum Membar_mask_bits {
StoreStore = ISHST,
LoadStore = ISHLD,
LoadLoad = ISHLD,
StoreLoad = ISH,
AnyAny = ISH
};
// templateTable_aarch64.cpp
// Issue a StoreStore barrier after all stores but before return
// from any constructor for any class with a final field. We don't
// know if this is a finalizer, so we always do so.
if (_desc->bytecode() == Bytecodes::_return)
__ membar(MacroAssembler::StoreStore);
final x = 9
的写操作之前是看不到x=9
的结果// templateTable_aarch64.cpp
// According to the new Java Memory Model (JMM):
// (1) All volatiles are serialized wrt to each other. ALSO reads &
// writes act as aquire & release, so:
// (2) A read cannot let unrelated NON-volatile memory refs that
// happen after the read float up to before the read. It's OK for
// non-volatile memory refs that happen before the volatile read to
// float down below it.
// (3) Similar a volatile write cannot let unrelated NON-volatile
// memory refs that happen BEFORE the write float down to after the
// write. It's OK for non-volatile memory refs that happen after the
// volatile write to float up before it.
// We only put in barriers around volatile refs (they are expensive),
// not _between_ memory refs (that would require us to track the
// flavor of the previous memory refs). Requirements (2) and (3)
// require some barriers before volatile stores and after volatile
// loads. These nearly cover requirement (1) but miss the
// volatile-store-volatile-load case. This final case is placed after
// volatile-stores although it could just as well go before
// volatile-loads.
// templateTable_arm.cpp
// StoreLoad barrier after volatile field write
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
__ b(skipMembar);
// StoreStore barrier after final field write
__ bind(notVolatile2);
volatile_barrier(MacroAssembler::StoreStore, Rtemp);
// 针对写操作
// Store为写屏障,作用就是防止重排序,同时让数据刷新到主内存
// Load为读屏障,作用就是使得当前工作线程的缓存失效,直接读取主内存数据,保证数据一致性
// for a volatile write
//
// dmb ish // store内存屏障 -- 防止重排序
// str<x> // 写volatile数据
// dmb ish // load内存屏障 -- 保证数据一致性(目的就是要看见最新的数据)
// other codes...
// for a final write
//
// dmb ishst // store内存屏障 -- 防止重排序
// final x = 9 // 写final数据
// dmb ishst // store内存屏障 -- 防止重排序
// other codes ...
Java语言规范
//ciField.cpp
// 源码中注释说明
// Is this field a constant?
//
// Clarification: A field is considered constant if:
// 1. The field is both static and final
// 2. The field is not one of the special static/final
// non-constant fields. These are java.lang.System.in
// and java.lang.System.out. Abomination.
JMM规范
使用final修饰的数据在字节码中显示带有ACC_FINAL
的访问标识符,对应访问标示符号的值为0x1000
final class XX
表明该Class不能被继承,说明该Class没有子类感谢花时间阅读,如果有用欢迎转发或者点个好看,谢谢!