在Java語言中,隨着語境的不一樣final關鍵字所表明的語義會有一些細微的差別。總的來講,final關鍵字表達的含義是「禁止修改」,這層有點相似於C++中的const關鍵字。之因此要採用final關鍵字,通常是會出於性能和設計層面的考慮。下文會具體討論final關鍵字在不一樣語境中的具體用法。html
用final關鍵字修飾的屬性,對於Java編譯器來講就是一個「常量」。其特色是:1.具體的值在編譯期間就已經被肯定;2.在運行時不能再被修改。基於以上兩個特色,咱們分別分析一下Java中具體的基本類型和引用類型:java
對於基本類型,其自己就存放於虛擬機棧內部,因爲這些基本類型都是與底層數據類型直接對應的,一些肯定的計算過程能夠直接在編譯期完成,優化了運行期的執行效率。c++
對於引用類型,咱們已知引用自己其實也是存放於虛擬機棧中,final關鍵字只限制了對這個引用的更改,並不會限制對引用所指的實例化對象的變動。緩存
綜上所述,咱們能夠看出,final關鍵在修飾屬性時,不論屬性類型,限制修改的範圍是固定在虛擬機棧內部的存儲。安全
空白(blank)final多線程
一個final屬性能夠定義的時候不賦予初始的值,可是在其實際使用以前一定須要被初始化,一般final屬性的初始化,只會位於構造函數中或者屬性定義時的表達式表達式。函數
若是一個方法若是被聲明爲final類型,包含了兩層含義:1.這個方法不能再被重寫(即方法自己不能再被修改);2.方法的調用過程採用內嵌機制,更爲高效(節約了入棧出棧的開銷,更爲高效,此時的final語義上有點相似於c++中的inline函數)。性能
須要注意的是,private關鍵字是不能和final連用的。若是一個父類包含了private final修飾的方法,根據private關鍵字的語義,子類中應該是能夠從新定義一個與父類中對應方法簽名一直的方法,可是final關鍵字的語義有說明了這個方法是不能被重寫的,產生了歧義。優化
Final修飾的形參spa
若是一個方法的形參用final關鍵字修飾,表示的含義就是在這個方法內部,這個形參的值是不能被修改的。有點相似於final屬性,若是final修飾的形參數據類型是一個引用,這裏只限制了這個引用自己被更改,並不會限制對引用指向實例化對象的修改。
一個類用final關鍵字修飾,其含義包括:1.這個類不能再被任何子類繼承,2.這個類內部的全部方法都默認是final方法。
Volatile的英文含義爲易變的、揮發的,在java語言中volatile關鍵字是一個類型修飾符。JAVA中Volatile的做用:強制每次都直接讀內存,阻止重排序,確保voltile類型的值一旦被寫入緩存一定會被當即更新到主存。
要真正理解volatile語義的做用,就必須優先搞懂volatile關鍵字相關的幾個概念。
在JAVA多線程環境下,每一個Java線程除了共享的虛擬機棧外和Java堆以外,還存在一個獨立私有的堆內存(默認狀況下大小爲512KB,在線程被建立時分配,能夠經過-Xss選項調節其默認值大小)。每一個線程獨立運行,彼此之間都不可見,線程的私有堆內存中保留了一份主內存的拷貝,只有在特定需求的狀況下才會與主存作交互(複製/刷新)。
JAVA內存模型示例圖
在有些場景下訪問程序變量會表現出與程序制定的順序不同。例如:編譯器能夠以優化的名義改變指令的順序,處理器也能夠不按照順序來執行指令等。一個Java程序在從源代碼到最終實際執行的指令序列之間,會經歷一系列的重排序過程:
這種任意改變指令順序的行爲在單線程的狀況下「彷佛」是無害有益的,可是若是換到多線程的狀況,因爲全部線程都獨立運行,不知道其餘線程在作什麼;若是多個線程批次之間還存在共享的內存區域,就必須解決同步的問題。
正是因爲JAVA中volatile關鍵字的這種語義,volatile能夠被認爲是一個輕量級的synchronized塊,但實際使用過程當中仍是有一些限制。
Volatile被正確使用的理想條件包括以下兩點:
說得很抽象,歸結起來就是一個volatile變量可以用來實現「輕量級的同步」,前提是這個變量自身不能同時被多個線程共享修改。
一般volatile的使用場景:存在多個線程同時運行,只有一個線程擁有對volatile屬性的修改權,其餘的線程只能進行讀操做。具體的示例參考模式有興趣的同窗能夠參考文章《JAVA理論與實踐》。
Volatile只能保證每次線程讀取到的變量來自最新的內存,保證修改操做可以及時反饋到主內存中,相對於synchronized鎖定內存的作法,volatile在讀取時擁有很大的性能上的優點。
Voltile關鍵字並不保證操做的原子性,例如一個自增操做i++,即便i被聲明爲voltile類型,在多線程的狀況下,i的值也會是不肯定的。
在JAVA中long類型和double類型都是64位長度,對於32位的機器這須要兩次讀內存的操做。在規範中,JAVA內存模型只在這種狀況下保證用voilate修飾的double和long類型變量的兩次讀操做變爲一個原子操做。
綜上所述,volatile關鍵字表現出了一種脆弱的同步機制,在沒法確認當前場景絕對知足的前提下,voilate關鍵字很難保證安全合理得被使用。但確實volatile爲咱們提供了在特定場景下更高的性能(相比synchronized)。