天天看點

java volatile 和Transient 關鍵字

java volatile 和Transient 關鍵字

java關鍵字volatile

volatile修飾的成員變量在每次被線程通路時,都強迫從主記憶體中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程将變化值回寫到主記憶體。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

java語言規範中指出:為了獲得最佳速度,允許線程儲存共享成員變量的私有拷貝,而且隻當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

這樣當多個線程同時與某個對象互動時,就必須要注意到要讓線程及時的得到共享成員變量的變化。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

而volatile關鍵字就是提示vm:對于這個成員變量不能儲存它的私有拷貝,而應直接與共享成員變量互動。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

使用建議:在兩個或者更多的線程通路的成員變量上使用volatile。當要通路的變量已在synchronized代碼塊中,或者為常量時,不必使用。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

由于使用volatile屏蔽掉了vm中必要的代碼優化,是以在效率上比較低,是以一定在必要時才使用此關鍵字。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

java關鍵字transient   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

轉自http://horst.sun.blog.163.com/blog/static/348849612007614494492/   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

翻譯自http://www.devx.com/tips/tip/13726。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

java的serialization提供了一種持久化對象執行個體的機制。當持久化對象時,可能有一個特殊的對象資料成員,我們不想   

java volatile 和Transient 關鍵字

用serialization機制來儲存它。為了在一個特定對象的一個域上關閉serialization,可以在這個域前加上關鍵字transient。   

java volatile 和Transient 關鍵字

transient是java語言的關鍵字,用來表示一個域不是該對象串行化的一部分。當一個對象被串行化的時候,transient型變量的值不包括在串行化的表示中,然而非transient型的變量是被包括進去的。  

注意static變量也是可以串行化的 

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

首先,讓我們看一些java serialization的代碼:   

java volatile 和Transient 關鍵字

public class logginginfo implements java.io.serializable   

java volatile 和Transient 關鍵字

{   

java volatile 和Transient 關鍵字

    private date loggingdate = new date();   

java volatile 和Transient 關鍵字

    private string uid;   

java volatile 和Transient 關鍵字

    private transient string pwd;   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

    logginginfo(string user, string password)   

java volatile 和Transient 關鍵字

    {   

java volatile 和Transient 關鍵字

        uid = user;   

java volatile 和Transient 關鍵字

        pwd = password;   

java volatile 和Transient 關鍵字

    }   

java volatile 和Transient 關鍵字

    public string tostring()   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

        string password=null;   

java volatile 和Transient 關鍵字

        if(pwd == null)   

java volatile 和Transient 關鍵字

        {   

java volatile 和Transient 關鍵字

        password = "not set";   

java volatile 和Transient 關鍵字

        }   

java volatile 和Transient 關鍵字

        else  

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

            password = pwd;   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

        return "logon info: \n   " + "user: " + uid +   

java volatile 和Transient 關鍵字

            "\n   logging date : " + loggingdate.tostring() +   

java volatile 和Transient 關鍵字

            "\n   password: " + password;   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

}   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

現在我們建立一個這個類的執行個體,并且串行化(serialize)它 ,然後将這個串行化對象寫如磁盤。   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

logginginfo loginfo = new logginginfo("mike", "mechanics");   

java volatile 和Transient 關鍵字

system.out.println(loginfo.tostring());   

java volatile 和Transient 關鍵字

try  

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

   objectoutputstream o = new objectoutputstream(   

java volatile 和Transient 關鍵字

                new fileoutputstream("loginfo.out"));   

java volatile 和Transient 關鍵字

   o.writeobject(loginfo);   

java volatile 和Transient 關鍵字

   o.close();   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

catch(exception e) {//deal with exception}   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

to read the object back, we can write   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

   objectinputstream in =new objectinputstream(   

java volatile 和Transient 關鍵字

                new fileinputstream("loginfo.out"));   

java volatile 和Transient 關鍵字

   logginginfo loginfo = (logginginfo)in.readobject();   

java volatile 和Transient 關鍵字

   system.out.println(loginfo.tostring());   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

如果我們運作這段代碼,我們會注意到從磁盤中讀回(read——back (de-serializing))的對象列印password為"not set"。這是當我們定義pwd域為transient時,所期望的正确結果。   

java volatile 和Transient 關鍵字

現在,讓我們來看一下粗心對待transient域可能引起的潛在問題。假設我們修改了類定義,提供給transient域一個預設值,   

java volatile 和Transient 關鍵字

代碼如下:   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

public class guestlogginginfo implements java.io.serializable   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

    guestlogginginfo()   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

        uid = "guest";   

java volatile 和Transient 關鍵字

        pwd = "guest";   

java volatile 和Transient 關鍵字
java volatile 和Transient 關鍵字

    public string tostring()       {   

        //same as above   

     }   

現在,如果我們穿行化guestlogginginfo的一個執行個體,将它寫入磁盤,并且再将它從磁盤中讀出,我們仍然看到讀回的對象列印password 為 "not set"。當從磁盤中讀出某個類的執行個體時,實際上并不會執行這個類的構造函數,   

而是載入了一個該類對象的持久化狀态,并将這個狀态指派給該類的另一個對象。