熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

關於Java自增操作的原子性

2013-11-23 19:29:13  來源: Java核心技術 
    最近在工作中和一個同事因為自增是不是原子性操作爭論的面紅耳赤那Java的自增操作到底是不是原子性操作呢答案是否的即Java的自增操作不是原子性操作
   
    首先我們先看看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中自增不是原子性操作它包含一個讀操作和一個寫操作
   
    以上可能還不能讓你信服要想讓人心服口服就必須用代碼說話正如FaceBook的文化一樣代碼贏得爭論那我們就看一段代碼
   
    以下的代碼是用個線程同時執行自增操作每個線程自增如果自增操作是原子性操作的話那麼執行完amount的值為運行代碼之後你會發現amount的值小於這就說明自增操作不是原子性的
   
    /**
   
    *
   
    * @author renrunwu
   
    */
   
    public class MultiThread implements Runnable {
   
        private int count;
   
        private int amount = ;
   
   
   
        public MultiThread() {
   
             count = ;
   
        }
   
   
   
        public MultiThread(int count) {
   
            unt = count;
   
        }
   
   
   
        @Override
   
        public void run() {
   
            for (int i = ; i < count; i++) {
   
                amount++;
   
            }
   
        }
   
   
   
        public static void main(String[] args) {
   
            ExecutorService executorService = ExecutorsnewCachedThreadPool()
   
            MultiThread multiThread =new MultiThread()
   
            for (int i = ; i < ; i++) {
   
                executorServiceexecute(multiThread)
   
            }
   
            executorServiceshutdown()
   
   
   
            try {
   
                Threadsleep(
   
            } catch (InterruptedException e) {
   
                eprintStackTrace()
   
            }
   
            Systemoutprintln(multiThreadamount)
   
        }
   
    }
   
    如果以上還不能讓你信服的話也沒關系我們就把自增操作反編譯出來看看java字節碼是怎麼操作的
   
    以下是一個簡單的自增操作代碼
   
    public class Increment {
   
        private int id = ;
   
        public void getNext(){
   
            id++;
   
        }
   
    }
   
    我們看看反編譯之後的Java字節碼主要關注getNext()方法內部的Java字節碼
   
    public class Increment extends javalangObject{
   
        public Increment()
   
          Code:
   
    :   aload_
   
    :   invokespecial   #; //Method java/lang/Object<init>:()V
   
    :   aload_
   
    :   iconst_
   
    :   putfield        #; //Field id:I
   
    :   return
   
   
   
        public void getNext()
   
          Code:
   
    :   aload_   //加載局部變量表index為的變量在這裡是this
   
    :   dup                 //將當前棧頂的對象引用復制一份
   
    :   getfield        #; //Field id:I獲取id的值並將其值壓入棧頂
   
    :   iconst_            //將int型的值壓入棧頂
   
    :   iadd                //將棧頂兩個int類型的元素相加並將其值壓入棧頂
   
    :   putfield        #; //Field id:I將棧頂的值賦值給id
   
    :  return
   
   
   
        }
   
    很明顯我們能夠看到在getNext()方法內部對於類變量id有一個先取值後加一再賦值的過程因此我們可以很肯定的說Java中的自增操作不是原子性的
   
    也許你會問那局部變量的自增操作是否是原子性的我們在看看一下代碼
   
    public class Increment {
   
        public void getNext(){
   
        int id = ;
   
            id++;
   
        }
   
    }
   
    我們再看看反編譯之後的Java字節碼主要還是關注getNext()方法內部的Java字節碼
   
    public class Increment extends javalangObject{
   
    public Increment()
   
      Code:
   
    :   aload_
   
    :   invokespecial   #; //Method java/lang/Object<init>:()V
   
    :   return
   
   
   
    public void getNext()
   
      Code:
   
    :   iconst_
   
    :   istore_
   
    :   iinc   
   
    :   return
   
   
   
    }
   
    與全局變量的自增操作相比很明顯局部變量的自增操作少了getfield與putfield操作而且對於局部變量來說它無論如何都不會涉及到多線程的操作因此局部變量的自增操作是否是原子操作也就顯得不那麼重要了
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26944.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.