transient和volatile兩個關鍵字區別
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中必要的程式碼優化,所以在效率上比較低,因此一定在必要時才使用此關鍵字。