隨筆-204  評論-149  文章-0  trackbacks-0
          Volatile修飾的成員變量在每次被線程訪問時,都強(qiáng)迫從主內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時,強(qiáng)迫線程將變化值回寫到主內(nèi)存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。   
            
          Java語言規(guī)范中指出:為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當(dāng)線程進(jìn)入或者離開同步代碼塊時才與共享成員變量的原始值對比。   
            
          這樣當(dāng)多個線程同時與某個對象交互時,就必須要注意到要讓線程及時的得到共享成員變量的變化。   
            
          而volatile關(guān)鍵字就是提示VM:對于這個成員變量不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。   
            
          使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當(dāng)要訪問的變量已在synchronized代碼塊中,或者為常量時,不必使用。   
            
          由于使用volatile屏蔽掉了VM中必要的代碼優(yōu)化,所以在效率上比較低,因此一定在必要時才使用此關(guān)鍵字。   
            
          java關(guān)鍵字Transient   
            
          轉(zhuǎn)自http:
          //horst.sun.blog.163.com/blog/static/348849612007614494492/   
            
          翻譯自http:
          //www.devx.com/tips/Tip/13726。   
            
          Java的serialization提供了一種持久化對象實(shí)例的機(jī)制。當(dāng)持久化對象時,可能有一個特殊的對象數(shù)據(jù)成員,我們不想   
          用serialization機(jī)制來保存它。為了在一個特定對象的一個域上關(guān)閉serialization,可以在這個域前加上關(guān)鍵字transient。   
          transient是Java語言的關(guān)鍵字,用來表示一個域不是該對象串行化的一部分。當(dāng)一個對象被串行化的時候,transient型變量的值不包括在串行化的表示中,然而非transient型的變量是被包括進(jìn)去的。  
          注意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;   
              }
             
          }
             
            
          現(xiàn)在我們創(chuàng)建一個這個類的實(shí)例,并且串行化(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   
            
          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}   
            
          如果我們運(yùn)行這段代碼,我們會注意到從磁盤中讀回(read——back (de
          -serializing))的對象打印password為"NOT SET"。這是當(dāng)我們定義pwd域?yàn)閠ransient時,所期望的正確結(jié)果。   
          現(xiàn)在,讓我們來看一下粗心對待transient域可能引起的潛在問題。假設(shè)我們修改了類定義,提供給transient域一個默認(rèn)值,   
          代碼如下:   
            
          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   
               }
             
          }
             
          現(xiàn)在,如果我們穿行化GuestLoggingInfo的一個實(shí)例,將它寫入磁盤,并且再將它從磁盤中讀出,我們?nèi)匀豢吹阶x回的對象打印password 為 
          "NOT SET"。當(dāng)從磁盤中讀出某個類的實(shí)例時,實(shí)際上并不會執(zhí)行這個類的構(gòu)造函數(shù),   
          而是載入了一個該類對象的持久化狀態(tài),并將這個狀態(tài)賦值給該類的另一個對象。  
          posted on 2009-06-20 18:23 Frank_Fang 閱讀(110484) 評論(26)  編輯  收藏 所屬分類: Java編程

          評論:
          # re: Java transient關(guān)鍵字[未登錄] 2011-06-17 16:35 | 1
          # re: Java transient關(guān)鍵字[未登錄] 2011-06-17 16:36 | 1
          # re: Java transient關(guān)鍵字[未登錄] 2011-08-05 14:41 | zg
          useful  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2011-09-11 21:35 |
          學(xué)習(xí)了 謝謝   回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2012-03-15 17:46 | ###
          非常不錯  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2012-06-28 09:58 | 大家點(diǎn)擊開
          受教了,多謝!  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2012-08-06 23:48 | aaa
          very good!!!  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2012-09-04 16:45 | 過客
          學(xué)習(xí)了,非常好!  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2012-10-11 07:40 | whoiam8485
          講得非常好,終于懂了  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2013-01-05 12:33 | bruce
          把private transient String pwd; 修改為private String pwd;
          我在機(jī)器上測試了下,不會輸出 "NOT SET"  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2013-05-30 10:13 | AlexSeeker
          “由于使用volatile屏蔽掉了VM中必要的代碼優(yōu)化,所以在效率上比較低,因此一定在必要時才使用此關(guān)鍵字。”

          volatile省略了把變量拷貝到線程的私有空間 和 從私有空間寫回到主內(nèi)存空間的過程,應(yīng)該是效率提高才對吧?!  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2013-08-08 09:50 | sleve
          @AlexSeeker
          這個拷貝實(shí)際作用就是一種緩存,“只當(dāng)線程進(jìn)入或者離開同步代碼塊時才與共享成員變量的原始值對比”,是一種優(yōu)化手段,而 volatile是取消了這種機(jī)制,每次都去“直接與共享成員變量交互”,所以效率要低,這話沒錯  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2013-11-03 10:28 | chump
          @bruce
          可以輸出  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2014-03-07 17:05 | lephix
          @AlexSeeker
          效率是低喲, 因?yàn)槿绻诰€程里面頻繁的獲取和修改該變量,那么都必須要到主內(nèi)存里面進(jìn)行操作,而優(yōu)化過的代碼可能會把該變量放在這個線程所在CPU的CACHE里面,而CACHE比MEM快,所以是變慢了。  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2014-05-09 09:47 | 來客
          @AlexSeeker
          確實(shí)省去了2次交互(子線程開始,結(jié)束的時候各跟主線程交互1次),但卻改成了動不動和主內(nèi)存交互。只要在子線程中每次讀或者改volatile變量值,就立刻從主內(nèi)存中讀取或?qū)懟氐街鲀?nèi)存。以前只是2次交互,現(xiàn)在可能N次了。  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2014-07-15 16:50 | sdf
          # re: Java transient關(guān)鍵字 2015-01-23 12:23 | blueocean
          言簡意賅  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2015-03-27 11:26 | anding
          a little useful  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2015-04-08 10:02 | xx
          你最前面對volatile的解釋有一半是錯誤的??!  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2015-12-10 17:47 | 穎輝小居
          錯的離譜最后幾句是完全錯的離譜啊,磁盤讀出的時候當(dāng)然不會執(zhí)行構(gòu)造了,構(gòu)造是你在存到磁盤的時候執(zhí)行的。你存到磁盤的時候是一個對象。這里肯定是new的就會執(zhí)行構(gòu)造了。那個關(guān)鍵字是在序列化為對象流的時候起作用的。屏蔽了pwd這個字段,不將他放入流中。磁盤里當(dāng)然就沒有這個屬性了。所有的對象只保存屬性,不保存函數(shù)。函數(shù)是功能,是在類中定義的。所有這個類的對象都能調(diào)用函數(shù),但是你傳遞對象的時候只有屬性。這個pwd沒有被序列化,就不會再磁盤里。讀出數(shù)據(jù)的時候(getPWD())也就沒有這個屬性值。  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2015-12-10 23:59 | DOUDOU
          解釋有誤  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2015-12-11 00:00 | DOUDOU
          最后幾句解釋的卻不太正確
            回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2016-03-13 20:11 | seancheer
          很不錯。  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字 2016-03-22 13:02 | 55
          # re: Java transient關(guān)鍵字 2016-04-07 14:50 | 333
          我想說static也不能被序列化。。。,附上說明:The readObject method is responsible for reading from the stream and restoring the classes fields. It may call in.defaultReadObject to invoke the default mechanism for restoring the object's non-static and non-transient fields  回復(fù)  更多評論
            
          # re: Java transient關(guān)鍵字[未登錄] 2016-04-10 20:20 | aa
          @AlexSeeker
          volatile屏蔽了重排序優(yōu)化  回復(fù)  更多評論
            
          主站蜘蛛池模板: 大关县| 壶关县| 时尚| 平泉县| 邹平县| 江油市| 闻喜县| 昌邑市| 汉寿县| 南平市| 新邵县| 通山县| 乐清市| 农安县| 清河县| 阿坝县| 桃江县| 西青区| 荣昌县| 蒙城县| 乌什县| 泸溪县| 观塘区| 新兴县| 和林格尔县| 湛江市| 句容市| 海南省| 平顶山市| 新营市| 睢宁县| 象山县| 诸暨市| 辉县市| 纳雍县| 石棉县| 清新县| 鹿邑县| 醴陵市| 南平市| 石家庄市|