Java i++和i=i+1在原子性方面的差异
我知道I++不是线程安全的操作。我也理解为什么I++比I=I+1还要快。在线程安全方面,i=i+1与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
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指令的生成只是为了增加局部变量。看一些例子。如果你对八月的答案有异议,你应该在答案下面加上评论,可能还有否决票。有人可能会用这个答案,甚至看不到你的答案。如果你对八月的答案有异议,你应该在这个答案下面加上评论,可能还有否决票。有人可能会用这个答案,甚至看不到你的答案。请检查这一个以了解差异。请检查这一个以了解差异