隨筆-204  評論-149  文章-0  trackbacks-0
          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   
            
          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"。當從磁盤中讀出某個類的實例時,實際上并不會執行這個類的構造函數,   
          而是載入了一個該類對象的持久化狀態,并將這個狀態賦值給該類的另一個對象。  
          posted on 2009-06-20 18:23 Frank_Fang 閱讀(110485) 評論(26)  編輯  收藏 所屬分類: Java編程

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

          volatile省略了把變量拷貝到線程的私有空間 和 從私有空間寫回到主內存空間的過程,應該是效率提高才對吧?!  回復  更多評論
            
          # re: Java transient關鍵字 2013-08-08 09:50 | sleve
          @AlexSeeker
          這個拷貝實際作用就是一種緩存,“只當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比”,是一種優化手段,而 volatile是取消了這種機制,每次都去“直接與共享成員變量交互”,所以效率要低,這話沒錯  回復  更多評論
            
          # re: Java transient關鍵字 2013-11-03 10:28 | chump
          @bruce
          可以輸出  回復  更多評論
            
          # re: Java transient關鍵字 2014-03-07 17:05 | lephix
          @AlexSeeker
          效率是低喲, 因為如果在線程里面頻繁的獲取和修改該變量,那么都必須要到主內存里面進行操作,而優化過的代碼可能會把該變量放在這個線程所在CPU的CACHE里面,而CACHE比MEM快,所以是變慢了。  回復  更多評論
            
          # re: Java transient關鍵字 2014-05-09 09:47 | 來客
          @AlexSeeker
          確實省去了2次交互(子線程開始,結束的時候各跟主線程交互1次),但卻改成了動不動和主內存交互。只要在子線程中每次讀或者改volatile變量值,就立刻從主內存中讀取或寫回到主內存。以前只是2次交互,現在可能N次了。  回復  更多評論
            
          # re: Java transient關鍵字 2014-07-15 16:50 | sdf
          sb  回復  更多評論
            
          # re: Java transient關鍵字 2015-01-23 12:23 | blueocean
          言簡意賅  回復  更多評論
            
          # re: Java transient關鍵字 2015-03-27 11:26 | anding
          a little useful  回復  更多評論
            
          # re: Java transient關鍵字[未登錄] 2015-04-08 10:02 | xx
          你最前面對volatile的解釋有一半是錯誤的!!  回復  更多評論
            
          # re: Java transient關鍵字 2015-12-10 17:47 | 穎輝小居
          錯的離譜最后幾句是完全錯的離譜啊,磁盤讀出的時候當然不會執行構造了,構造是你在存到磁盤的時候執行的。你存到磁盤的時候是一個對象。這里肯定是new的就會執行構造了。那個關鍵字是在序列化為對象流的時候起作用的。屏蔽了pwd這個字段,不將他放入流中。磁盤里當然就沒有這個屬性了。所有的對象只保存屬性,不保存函數。函數是功能,是在類中定義的。所有這個類的對象都能調用函數,但是你傳遞對象的時候只有屬性。這個pwd沒有被序列化,就不會再磁盤里。讀出數據的時候(getPWD())也就沒有這個屬性值。  回復  更多評論
            
          # re: Java transient關鍵字[未登錄] 2015-12-10 23:59 | DOUDOU
          解釋有誤  回復  更多評論
            
          # re: Java transient關鍵字[未登錄] 2015-12-11 00:00 | DOUDOU
          最后幾句解釋的卻不太正確
            回復  更多評論
            
          # re: Java transient關鍵字 2016-03-13 20:11 | seancheer
          很不錯。  回復  更多評論
            
          # re: Java transient關鍵字 2016-03-22 13:02 | 55
          555  回復  更多評論
            
          # re: Java transient關鍵字 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  回復  更多評論
            
          # re: Java transient關鍵字[未登錄] 2016-04-10 20:20 | aa
          @AlexSeeker
          volatile屏蔽了重排序優化  回復  更多評論
            
          主站蜘蛛池模板: 安塞县| 广宗县| 兴宁市| 嘉兴市| 沾化县| 九龙县| 贵溪市| 汽车| 五峰| 泸水县| 波密县| 康乐县| 晋州市| 屯门区| 嘉义县| 宣威市| 惠州市| 班戈县| 社旗县| 黑山县| 西宁市| 长汀县| 陵川县| 永仁县| 如皋市| 皮山县| 灵璧县| 都匀市| 高淳县| 中江县| 任丘市| 静安区| 道孚县| 惠东县| 遵义市| 富平县| 高唐县| 新密市| 张家港市| 丹阳市| 渭源县|