transient和volatile兩個關鍵字一個用於對象序列化,一個用於線程同步,都是Java中比較高階的話題,簡單總結一下。
transient
transient是類型修飾符,只能用來修飾欄位。在對象序列化的過程中,標記為transient的變數不會被序列化。
樣本:
class Test {
transient int a; // 不會被持久化
int b; // 持久化
}
當類Test的執行個體對象被序列化(比如將Test類的執行個體對象 t 寫入硬碟的文字檔t.txt中),變數 a 的內容不會被儲存,變數 b 的內容則會被儲存。
參考:
把一個對象的表示轉化為位元組流的過程稱為序列化(也稱為序列化,serialization),從位元組流中把對象重建出來稱為反序列化(也稱為為還原序列化,deserialization)。transient 為不應被序列化的資料提供了一個語言級的標記資料方法。
volatile
volatile也是變數修飾符,只能用來修飾變數。volatile修飾的成員變數在每次被線程訪問時,都強迫從共用記憶體中重讀該成員變數的值。而且,當成員變數發生變化時,強迫線程將變化值回寫到共用記憶體。這樣在任何時刻,兩個不同的線程總是看到某個成員變數的同一個值。
在此解釋一下Java的記憶體機制:
Java使用一個主記憶體來儲存變數當前值,而每個線程則有其獨立的工作記憶體。線程訪問變數的時候會將變數的值拷貝到自己的工作記憶體中,這樣,當線程對自己工作記憶體中的變數進行操作之後,就造成了工作記憶體中的變數拷貝的值與主記憶體中的變數值不同。
Java語言規範中指出:為了獲得最佳速度,允許線程儲存共用成員變數的私人拷貝,而且只當線程進入或者離開同步代碼塊時才與共用成員變數的原始值對比。
這樣當多個線程同時與某個對象互動時,就必須要注意到要讓線程及時的得到共用成員變數的變化。
而volatile關鍵字就是提示VM:對於這個成員變數不能儲存它的私人拷貝,而應直接與共用成員變數互動。
使用建議:在兩個或者更多的線程訪問的成員變數上使用volatile。當要訪問的變數已在synchronized代碼塊中,或者為常量時,不必使用。
由於使用volatile屏蔽掉了VM中必要的代碼最佳化,所以在效率上比較低,因此一定在必要時才使用此關鍵字。