qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          關于Java自增操作的原子性

           最近在工作中和一個同事因為自增是不是原子性操作爭論的面紅耳赤,那Java的自增操作到底是不是原子性操作呢,答案是否的,即Java的自增操作不是原子性操作。

            1、首先我們先看看Bruce Eckel是怎么說的:

            In the JVM an increment is not atomic and involves both a read and a write. (via the latest Java Performance Tuning Newsletter)

            意思很簡單,就是說在jvm中自增不是原子性操作,它包含一個讀操作和一個寫操作。

            2、以上可能還不能讓你信服,要想讓人心服口服,就必須用代碼說話。正如FaceBook的文化一樣:代碼贏得爭論。那我們就看一段代碼:

            以下的代碼是用100個線程同時執行自增操作,每個線程自增100次,如果自增操作是原子性操作的話,那么執行完amount的值為10,000。運行代碼之后,你會發現amount的值小于10,000,這就說明自增操作不是原子性的

          1. /** 
          2.  *  
          3.  * @author renrun.wu 
          4.  */ 
          5. public class MultiThread implements Runnable {  
          6.     private int count;  
          7.     private int amount = 1;  
          8.       
          9.     public MultiThread() {  
          10.          count = 100;  
          11.     }  
          12.       
          13.     public MultiThread(int count) {  
          14.         this.count = count;  
          15.     }  
          16.       
          17.     @Override 
          18.     public void run() {  
          19.         for (int i = 0; i < count; i++) {  
          20.             amount++;  
          21.         }  
          22.     }  
          23.       
          24.     public static void main(String[] args) {  
          25.         ExecutorService executorService = Executors.newCachedThreadPool();  
          26.         MultiThread multiThread =new MultiThread();  
          27.         for (int i = 0; i < 100; i++) {  
          28.             executorService.execute(multiThread);  
          29.         }  
          30.         executorService.shutdown();  
          31.           
          32.         try {  
          33.             Thread.sleep(60000);  
          34.         } catch (InterruptedException e) {  
          35.             e.printStackTrace();  
          36.         }  
          37.         System.out.println(multiThread.amount);  
          38.     }  
          39. }

            3、如果以上還不能讓你信服的話,也沒關系。我們就把自增操作反編譯出來,看看java字節碼是怎么操作的

            以下是一個簡單的自增操作代碼

          1. public class Increment {  
          2.     private int id = 0;  
          3.     public void getNext(){  
          4.         id++;  
          5.     }  
          6. }


           我們看看反編譯之后的Java字節碼,主要關注getNext()方法內部的Java字節碼。

          1. public class Increment extends java.lang.Object{  
          2.     public Increment();  
          3.       Code:  
          4. :   aload_0  
          5. :   invokespecial   #1//Method java/lang/Object."<init>":()V  
          6. :   aload_0  
          7. :   iconst_0  
          8. :   putfield        #2//Field id:I  
          9. :   return 
          10.  
          11.     public void getNext();  
          12.       Code:  
          13. :   aload_0   //加載局部變量表index為0的變量,在這里是this   
          14. :   dup                 //將當前棧頂的對象引用復制一份  
          15. :   getfield        #2//Field id:I,獲取id的值,并將其值壓入棧頂  
          16. :   iconst_1            //將int型的值1壓入棧頂  
          17. :   iadd                //將棧頂兩個int類型的元素相加,并將其值壓入棧頂  
          18. :   putfield        #2//Field id:I,將棧頂的值賦值給id  
          19. :  return 
          20.  
          21.     }

            很明顯,我們能夠看到在getNext()方法內部,對于類變量id有一個先取值后加一再賦值的過程。因此,我們可以很肯定的說Java中的自增操作不是原子性的。

            4、也許你會問,那局部變量的自增操作是否是原子性的。好,我們在看看一下代碼:

          1. public class Increment {  
          2.     public void getNext(){  
          3.     int id = 0;  
          4.         id++;  
          5.     }  
          6. }

            我們再看看反編譯之后的Java字節碼,主要還是關注getNext()方法內部的Java字節碼。

          1. public class Increment extends java.lang.Object{  
          2. public Increment();  
          3.   Code:  
          4. :   aload_0  
          5. :   invokespecial   #1//Method java/lang/Object."<init>":()V  
          6. :   return 
          7.  
          8. public void getNext();  
          9.   Code:  
          10. :   iconst_0  
          11. :   istore_1  
          12. :   iinc    11 
          13. :   return 
          14.  
          15. }

            與全局變量的自增操作相比,很明顯局部變量的自增操作少了getfield與putfield操作。而且對于局部變量來說,它無論如何都不會涉及到多線程的操作,因此局部變量的自增操作是否是原子操作也就顯得不那么重要了。

          posted on 2012-05-25 10:12 順其自然EVO 閱讀(191) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2012年5月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 嘉义市| 西城区| 武陟县| 闽清县| 黄骅市| 佳木斯市| 永定县| 达州市| 哈巴河县| 榆林市| 乐业县| 东乌珠穆沁旗| 松桃| 永年县| 新乡市| 大足县| 斗六市| 花莲市| 保德县| 丰镇市| 确山县| 横峰县| 宁明县| 义马市| 钟山县| 绍兴市| 繁昌县| 准格尔旗| 方正县| 塘沽区| 天柱县| 新宁县| 阿尔山市| 西畴县| 虹口区| 米脂县| 扎兰屯市| 安陆市| 陕西省| 龙岩市| 禹州市|