對於final修飾的變數,其實有兩個與指重排相關的規則
我們所書寫的**順序和jvm執行的指令順序不一定是相同的,jvm會在不影響執行正確性的前提下對指令進行重排序,以達到提高執行效率的目的。當然,這個正確性指的是單執行緒下的正確性,如果是多執行緒的話,jvm是無法判斷的。
如果final變數在建構函式中進行賦值,那麼在編譯的時候,該賦值操作後面就會生成乙個storestore記憶體屏障,用來保證建構函式返回之前,final變數必須賦值完成,以此來保證資料正確性。
而對於普通變數是沒有這個機制的,所以,如果普通內部變數在物件建構函式中賦值,普通變數的賦值操作可能會發生逃逸。乙個執行緒構造了這個物件,另乙個執行緒訪問這個物件,如果訪問成功說明這個物件的建構函式已經執行完了,並且按理來說普通變數應該也已經賦值完成了,但是因為指令重排,普通變數的賦值操作可能逃逸出建構函式外了,導致普通變數的賦值有可能還未完成,此時訪問這個普通變數就會出現問題,而final變數不會有這個問題:
如果物件中包含final域,初次訪問這個物件,和初次訪問這個物件的final域,這兩個操作不允許重排序。這是因為,如果訪問物件,說明物件的構造方法已經執行完畢了,也說明final變數也進行賦值了。那麼不會有問題;如果發生指令重排,先去訪問final變數,此時就會讀到還未賦值的final變數,就會出現問題。
具體的實現呢就是在編譯的時候,在final變數讀操作的前面加上乙個loadload記憶體屏障,來禁止指令重排
static關鍵字 final 關鍵字
特點 隨著類的載入而載入,也就是說靜態會隨著類的消失而消失,說明他的生命週期最長 靜態變數 static 關鍵字修飾成員變數,使用 類名.變數名 的形式來訪問,也可以使用 例項物件.變數名 的形式來訪問。靜態方法 static 關鍵字修飾成員函式,靜態方法可以使用 類名.方法名 的形式來訪問,也可以...
static關鍵字 final關鍵字
static關鍵字 靜態的 1,特點 可以修飾成員變數,成員方法 隨著類的載入而載入,優先於物件載入 只載入一次,就會一直存在,不再開闢新空間 全域性唯一,全域性共享 可以直接被類名呼叫 靜態只能呼叫靜態,非靜態可以隨意呼叫 總結 1,被static修飾後的特點 全域性共享 可以被類名直接呼叫 載入...
static 關鍵字 final關鍵字
一旦用了static 關鍵字,就不在屬於物件自己 而是屬於類。這個類裡的物件,都共享乙份。沒有static關鍵字那麼首先建立物件然後在通過物件才能使用它。靜態不能直接訪問非靜態 原因 在記憶體中是現有的靜態內容 後 有的非靜態內容 靜態方法中不能用this 原因this代表當前物件,通過誰呼叫的方法...