Java i++和i=i+1在原子性方面的差异

Java i++和i=i+1在原子性方面的差异,java,thread-safety,atomicity,Java,Thread Safety,Atomicity,我知道I++不是线程安全的操作。我也理解为什么I++比I=I+1还要快。在线程安全方面,i=i+1与i++有什么不同吗?任何字节码级别的解释都会非常有用。在字节码方面,i++和i+=1之间没有区别: 增量来源: 增量字节码: public static void main(java.lang.String[]); Code: 0: iconst_0 1: istore_1 2: iinc 1, 1

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

在字节码方面,i++和i+=1之间没有区别:

增量来源:

增量字节码:

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

复合加法字节码:

public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iinc          1, 1
       5: return
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; }

在字节码方面,i++和i+=1之间没有区别:

增量来源:

增量字节码:

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

复合加法字节码:

public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iinc          1, 1
       5: return
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; }

i++和i=i+1在这些方面没有区别。

i++和i=i+1在这些方面没有区别。

i+=1和i++都不是原子的,也不是线程安全的。++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);
    }

}
显然,有些文字丢失了。有一篇很好的博客文章,解释了这一点。这篇文章还指出@August的回答具有误导性。字节码iinc只为递增的局部变量生成,从线程安全的角度来看,这并不有趣。这篇博文还讨论了用于增量的不同字节码。

i+=1和i++都不是原子的,也不是线程安全的。++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);
    }

}

显然,有些文字丢失了。有一篇很好的博客文章,解释了这一点。这篇文章还指出@August的回答具有误导性。字节码iinc只为递增的局部变量生成,从线程安全的角度来看,这并不有趣。这篇博文还讨论了用于增量的不同字节码。

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

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

它们编译为,因此它们应该具有相同的性能。@August2-Nice。您应该将其作为答案发布。它们编译为,因此应该具有相同的性能。@August2-Nice。你应该把它作为一个答案发布。你如何从编译的源代码中读取字节码?@DavidJones你可以使用javap-cfoo.class或我的相当蹩脚的代码。你应该编辑你的答案,指出iinc指令只是为了增加局部变量而生成的。有关一些示例,请参阅。如何从已编译源代码读取字节码?@DavidJones您可以使用javap-c Foo.class或我的相当蹩脚的代码。您应该编辑您的答案,指出iinc指令的生成只是为了增加局部变量。看一些例子。如果你对八月的答案有异议,你应该在答案下面加上评论,可能还有否决票。有人可能会用这个答案,甚至看不到你的答案。如果你对八月的答案有异议,你应该在这个答案下面加上评论,可能还有否决票。有人可能会用这个答案,甚至看不到你的答案。请检查这一个以了解差异。请检查这一个以了解差异