2014-12-02 80 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++将导致相同的优化代码。

相关问题