在原子性方面,i ++和i = i + 1之间的差异

时间:2014-12-02 04:01:14

标签: java thread-safety atomicity

我知道i ++不是一个线程安全的操作。我也理解为什么i ++比i = i + 1更快。在线程安全方面,i = i + 1与i ++有什么不同吗?任何字节码级别的解释都会非常有用。

4 个答案:

答案 0 :(得分: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,可以解释这一点。那篇文章还指出@ August的回答是误导性的。该字节码(iinc)仅用于递增局部变量,这从线程安全的角度来看并不令人感兴趣。 (该博客文章还讨论了用于增量的不同字节码。)

答案 1 :(得分: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 

用于递增字段的字节码也是相同的,尽管它没有使用iinc指令(因为它需要一个局部变量索引):

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    

答案 2 :(得分:1)

i=i+1使用二进制运算符(+)加载i的值,并向其中加1,然后将结果存储回i。相反,i++使用一元(++)运算符,它只使用单个汇编指令递增值,因此理论上它可能更有效。但是,今天的编译器优化i=i+1i++会产生相同的优化代码。

答案 3 :(得分:-1)

在这些术语中,i ++和i = i + 1之间没有差异。