2014-12-02 120 views
1

我知道i ++不是線程安全操作。我也明白爲什麼我++也比我= i + 1更快。在線程安全方面,i = i + 1與i ++有什麼不同?任何字節碼級別的解釋都會很有幫助。就原子性而言,i ++和i = i + 1之間的區別

+7

它們編譯爲[相同的字節碼](http://pastebin.com/raw.php?i=G6Hadz8Q),所以它們應該具有相同的性能。 – August 2014-12-02 04:03:00

+1

@ August2 - 尼斯。您應該將其作爲答案發布。 – EJK 2014-12-02 04:05:44

回答

9

i += 1i++都不是原子的(都不是線程安全的)。 ++i也是如此。這裏有一個簡單的測試,你可以運行來證明這一點:

public class Test { 

    static volatile int x, y; 

    static class IncThread extends Thread { 
     public void run() { 
      for (int i=0; i<50000; i++) x++; 
      for (int i=0; i<50000; i++) y = y+1; 
     } 
    } 

    public static void main(String[] args) throws InterruptedException { 
     Thread t1 = new IncThread(); 
     Thread t2 = new IncThread(); 
     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
     System.out.printf("x = %d, y = %d%n", x, y); 
    } 

} 

這是我得到的輸出:

x = 99897, y = 81556 

顯然,一些寫的迷路了。有一個很好的小博客文章,++ not considered atomic,解釋這一點。這篇文章也指出@八月的答案是誤導性的。該字節碼(iinc)僅用於增加局部變量,這從線程安全的角度來看並不令人感興趣。 (博客文章還討論了用於增量的不同字節碼。)

+0

如果您在8月份的回答中遇到問題,您應該在該答案下發表評論,並且可能會降低評分。有人可能會使用這個答案,甚至沒有看到你的答案。 – 2014-12-02 04:35:27

6

還有就是,字節代碼明智i++i += 1之間沒有差異:

增量(來源):

public static void main(String[] args) { 
    int i = 0; 
    i++; 
} 

增量(字節碼):

public static void main(java.lang.String[]); 
    Code: 
     0: iconst_0  
     1: istore_1  
     2: iinc   1, 1 
     5: return 

化合物加成(來源):

public static void main(String[] args) { 
    int i = 0; 
    i += 1; 
} 

化合物加成(字節碼):

public static void main(java.lang.String[]); 
    Code: 
     0: iconst_0  
     1: istore_1  
     2: iinc   1, 1 
     5: return 

用於遞增字段字節碼也是相同的,儘管它不使用(因爲它需要一個局部變量索引):

int x; 

void inc() { x++; } 
void assign() { x += 1; } 

void inc(); 
    Code: 
     0: aload_0  
     1: dup   
     2: getfield  #2     // Field x:I 
     5: iconst_1  
     6: iadd   
     7: putfield  #2     // Field x:I 
     10: return   

    void assign(); 
    Code: 
     0: aload_0  
     1: dup   
     2: getfield  #2     // Field x:I 
     5: iconst_1  
     6: iadd   
     7: putfield  #2     // Field x:I 
     10: return  
+0

如何從編譯源代碼讀取字節碼? – 2014-12-02 04:16:55

+2

@DavidJones你可以使用'javap -c Foo。(或我相當蹩腳的[網站](http://bytes.i-i.im/)) – August 2014-12-02 04:18:53

+0

酷!謝謝... – 2014-12-02 04:19:42

-1

在這些術語中,i ++和i = i + 1沒有區別。

+0

請檢查這些以瞭解差異http://stackoverflow.com/a/29559727/4025692 – 2015-04-10 11:17:34

1

i=i+1使用一個二元運算符(+)加載i的值,並將其加1,然後將結果存回i中。相比之下,i++使用一元(++)運算符,它使用單個彙編指令簡單地增加該值,因此理論上它可能更高效。然而,今天的編譯器優化i=i+1i++將導致相同的優化代碼。

相關問題