java關鍵字volatile
volatile修飾的成員變量在每次被線程通路時,都強迫從主記憶體中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程将變化值回寫到主記憶體。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。
java語言規範中指出:為了獲得最佳速度,允許線程儲存共享成員變量的私有拷貝,而且隻當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。
這樣當多個線程同時與某個對象互動時,就必須要注意到要讓線程及時的得到共享成員變量的變化。
而volatile關鍵字就是提示vm:對于這個成員變量不能儲存它的私有拷貝,而應直接與共享成員變量互動。
使用建議:在兩個或者更多的線程通路的成員變量上使用volatile。當要通路的變量已在synchronized代碼塊中,或者為常量時,不必使用。
由于使用volatile屏蔽掉了vm中必要的代碼優化,是以在效率上比較低,是以一定在必要時才使用此關鍵字。
java關鍵字transient
轉自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)它 ,然後将這個串行化對象寫如磁盤。
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
objectinputstream in =new objectinputstream(
new fileinputstream("loginfo.out"));
logginginfo loginfo = (logginginfo)in.readobject();
system.out.println(loginfo.tostring());
如果我們運作這段代碼,我們會注意到從磁盤中讀回(read——back (de-serializing))的對象列印password為"not set"。這是當我們定義pwd域為transient時,所期望的正确結果。
現在,讓我們來看一下粗心對待transient域可能引起的潛在問題。假設我們修改了類定義,提供給transient域一個預設值,
代碼如下:
public class guestlogginginfo implements java.io.serializable
guestlogginginfo()
uid = "guest";
pwd = "guest";
public string tostring() {
//same as above
}
現在,如果我們穿行化guestlogginginfo的一個執行個體,将它寫入磁盤,并且再将它從磁盤中讀出,我們仍然看到讀回的對象列印password 為 "not set"。當從磁盤中讀出某個類的執行個體時,實際上并不會執行這個類的構造函數,
而是載入了一個該類對象的持久化狀态,并将這個狀态指派給該類的另一個對象。