隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0

          導航

          <2009年3月>
          22232425262728
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          公告

          關注我的新浪微博

          我的著作









          常用鏈接

          留言簿(126)

          我參與的團隊

          隨筆分類(818)

          隨筆檔案(310)

          文章分類(1)

          文章檔案(8)

          相冊

          ADSL、3G查詢

          CSDN

          eclipse

          ibm

          Java EE

          Linux

          Web

          云服務

          代理網站

          關注的網站

          協議

          喜歡的Blog

          國內廣告平臺

          圖書出版

          在線培訓

          開發工具

          微博客戶端

          手機鈴聲

          操作系統

          • ReactOS
          • 一個與windowXP/2003兼容的操作系統

          數學

          文件格式

          源碼資源

          移動(Mobile)

          編程語言

          英語學習

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 1973206
          • 排名 - 6

          最新評論

          閱讀排行榜

          評論排行榜

          Java多線程初學者指南(6):慎重使用volatile關鍵字

          本文為原創,如需轉載,請注明作者和出處,謝謝!

          上一篇:Java多線程初學者指南(5):join方法的使用

              volatile關鍵字相信了解Java多線程的讀者都很清楚它的作用。volatile關鍵字用于聲明簡單類型變量,如int、float、boolean等數據類型。如果這些簡單數據類型聲明為volatile,對它們的操作就會變成原子級別的。但這有一定的限制。例如,下面的例子中的n就不是原子級別的:

          package mythread;

          public class JoinThread extends Thread
          {
              
          public static volatile int n = 0;
              public void run()
              {
                  
          for (int i = 0; i < 10; i++)
                      
          try
                  {
                          n 
          = n + 1;
                          sleep(
          3); // 為了使運行結果更隨機,延遲3毫秒

                      }
                      
          catch (Exception e)
                      {
                      }
              }

              
          public static void main(String[] args) throws Exception
              {

                  Thread threads[] 
          = new Thread[100];
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 建立100個線程
                      threads[i] = new JoinThread();
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 運行剛才建立的100個線程
                      threads[i].start();
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 100個線程都執行完后繼續
                      threads[i].join();
                  System.out.println(
          "n=" + JoinThread.n);
              }
          }

               如果對n的操作是原子級別的,最后輸出的結果應該為n=1000,而在執行上面積代碼時,很多時侯輸出的n都小于1000,這說明n=n+1不是原子級別的操作。原因是聲明為volatile的簡單變量如果當前值由該變量以前的值相關,那么volatile關鍵字不起作用,也就是說如下的表達式都不是原子操作:

          = n + 1;
          n
          ++;

                如果要想使這種情況變成原子操作,需要使用synchronized關鍵字,如上的代碼可以改成如下的形式:
          package mythread;

          public class JoinThread extends Thread
          {
              
          public static int n = 0;

              
          public static synchronized void inc()
              {
                  n
          ++;
              }
              
          public void run()
              {
                  
          for (int i = 0; i < 10; i++)
                      
          try
                      {
                          inc(); 
          // n = n + 1 改成了 inc();
                          sleep(3); // 為了使運行結果更隨機,延遲3毫秒

                      }
                      
          catch (Exception e)
                      {
                      }
              }

              
          public static void main(String[] args) throws Exception
              {

                  Thread threads[] 
          = new Thread[100];
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 建立100個線程
                      threads[i] = new JoinThread();
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 運行剛才建立的100個線程
                      threads[i].start();
                  
          for (int i = 0; i < threads.length; i++)
                      
          // 100個線程都執行完后繼續
                      threads[i].join();
                  System.out.println(
          "n=" + JoinThread.n);
              }
          }

              上面的代碼將n=n+1改成了inc(),其中inc方法使用了synchronized關鍵字進行方法同步。因此,在使用volatile關鍵字時要慎重,并不是只要簡單類型變量使用volatile修飾,對這個變量的所有操作都是原來操作,當變量的值由自身的上一個決定時,如n=n+1、n++等,volatile關鍵字將失效,只有當變量的值和自身上一個值無關時對該變量的操作才是原子級別的,如n = m + 1,這個就是原級別的。所以在使用volatile關鍵時一定要謹慎,如果自己沒有把握,可以使用synchronized來代替volatile。

          下一篇:Java多線程初學者指南(7):向線程傳遞數據的三種方法
               




          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2009-03-14 16:44 銀河使者 閱讀(9413) 評論(10)  編輯  收藏 所屬分類: java 原創多線程

          評論

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          使用volatile關鍵字時該變量必須獨立于程序的其他內容和這個變量以前的值。
          btw:n++的動作實際由“讀,添加,寫”三個步驟組成的,并不是原子操作。
          2009-03-15 09:00 | Leo1734

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          volatile的原子操作是將讀、寫合二為一了,保證了其他線程讀取變量時總是最新的,如果變量的值和自身以前的值相關,則volatile不起作用,如n++、n=n-1等。
          2009-03-15 09:19 | 銀河使者

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          @Leo1734
          如果從bytecode角度看,Java源代碼級的很多操作都不是原子的,javac將其編譯成bytecode時都有多步組成。n = m也是由多步組成的,不過要給n加上volatile,n=m就是原子級的操作。
          2009-03-15 09:21 | 銀河使者

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          受教了,謝謝各位
          2009-03-15 11:59 | 習習

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字[未登錄]  回復  更多評論   

          volatile是保證變量對其他線程的可見性
          2009-03-16 11:46 | jbahamut

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          其實我覺得這個問題應該是線程的問題,主要是線程執行的時間可能有兩個同時獲取這個int值,然后第一個線程增加后,第二個線程在增加,覆蓋了其值,主要是線程沒有對n 這個變量加鎖,造成多個線程同時讀取相同的值
          2009-03-16 13:21 | guming123416

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          @guming123416
          至于為什么volatile在某些時候不好使,這得問JVM了,可能是實現機制的問題,如果想保險點,應盡量少用volatile。thanking in java的作者也建議少用volatile。
          2009-03-16 13:52 | 銀河使者

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          你上面的我兩個在JDK1.6上執行都是n=1000啊,似乎volatile有用,這還是原子操作哈
          2009-03-19 19:21 | qiulijian

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          @qiulijian
          你多運行幾次,如運行20次再說,第一個例子不同步,第二個例子是同步的
          2009-03-19 19:29 | 銀河使者

          # re: Java多線程初學者指南(6):慎重使用volatile關鍵字  回復  更多評論   

          這里有自動拆封箱操作,n的對象一直在變化。
          2015-08-26 16:40 | 皮鞋錚亮
          主站蜘蛛池模板: 丽水市| 上思县| 宁阳县| 麻城市| 乐业县| 武定县| 钦州市| 朝阳县| 闽清县| 游戏| 房产| 阿瓦提县| 长海县| 安吉县| 繁昌县| 新泰市| 黑河市| 宕昌县| 天柱县| 舞钢市| 巴彦淖尔市| 武强县| 玛曲县| 新化县| 商都县| 正定县| 洪湖市| 桓仁| 济源市| 正安县| 呼和浩特市| 东城区| 汝州市| 崇阳县| 岐山县| 天峨县| 昆明市| 牟定县| 叙永县| 疏附县| 丰原市|