Volatile修飾的成員變量在每次被線程訪問時,都強迫從主內存中重讀該成員變量的值。並且,當成員變量發生變化時,強迫線程將變化值回寫到主內存。這樣在任什麼時候刻,兩個不一樣的線程老是看到某個成員變量的同一個值。
Java語言規範中指出:爲了得到最佳速度,容許線程保存共享成員變量的私有拷貝,並且只當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。
這樣當多個線程同時與某個對象交互時,就必需要注意到要讓線程及時的獲得共享成員變量的變化。 java
而volatile關鍵字就是提示VM:對於這個成員變量不能保存它的私有拷貝,而應直接與共享成員變量交互。 函數
使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當要訪問的變量已在synchronized代碼塊中,或者爲常量時,沒必要使用。 優化
因爲使用volatile屏蔽掉了VM中必要的代碼優化,因此在效率上比較低,所以必定在必要時才使用此關鍵字。
java關鍵字Transient ui
轉自http://horst.sun.blog.163.com/blog/static/348849612007614494492/
翻譯自http://www.devx.com/tips/Tip/13726。 線程
Java的serialization提供了一種持久化對象實例的機制。當持久化對象時,可能有一個特殊的對象數據成員,咱們不想
用serialization機制來保存它。爲了在一個特定對象的一個域上關閉serialization,能夠在這個域前加上關鍵字transient。
transient是Java語言的關鍵字,用來表示一個域不是該對象串行化的一部分。當一個對象被串行化的時候,transient型變量的值不包括在串行化的表示中,然而非transient型的變量是被包括進去的。
注意static變量也是能夠串行化的
首先,讓咱們看一些Java serialization的代碼: 翻譯
public class LoggingInfo implements java.io.Serializable { private Date loggingDate = new Date(); private String uid; private transient String pwd; LoggingInfo(String user, String password) { uid = user; pwd = password; } public String toString() { String password=null; if(pwd == null) { password = "NOT SET"; } else { password = pwd; } return "logon info: \n " + "user: " + uid + "\n logging date : " + loggingDate.toString() + "\n password: " + password; } }
如今咱們建立一個這個類的實例,而且串行化(serialize)它 ,而後將這個串行化對象寫如磁盤。
code
LoggingInfo logInfo = new LoggingInfo("MIKE", "MECHANICS"); System.out.println(logInfo.toString()); try { ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("logInfo.out")); o.writeObject(logInfo); o.close(); } catch(Exception e) {//deal with exception} To read the object back, we can write try { ObjectInputStream in =new ObjectInputStream( new FileInputStream("logInfo.out")); LoggingInfo logInfo = (LoggingInfo)in.readObject(); System.out.println(logInfo.toString()); } catch(Exception e) {//deal with exception}
若是咱們運行這段代碼,咱們會注意到從磁盤中讀回(read——back (de-serializing))的對象打印password爲"NOT SET"。這是當咱們定義pwd域爲transient時,所指望的正確結果。
如今,讓咱們來看一下粗心對待transient域可能引發的潛在問題。假設咱們修改了類定義,提供給transient域一個默認值,
代碼以下:
對象
public class GuestLoggingInfo implements java.io.Serializable { private Date loggingDate = new Date(); private String uid; private transient String pwd; GuestLoggingInfo() { uid = "guest"; pwd = "guest"; } public String toString() { //same as above } }
如今,若是咱們穿行化GuestLoggingInfo的一個實例,將它寫入磁盤,而且再將它從磁盤中讀出,咱們仍然看到讀回的對象打印password 爲 "NOT SET"。當從磁盤中讀出某個類的實例時,實際上並不會執行這個類的構造函數,
而是載入了一個該類對象的持久化狀態,並將這個狀態賦值給該類的另外一個對象。 blog