Java 从字节码的角度来看i++

本文探讨了Java中i++操作的非原子性,并通过字节码分析揭示其背后的原因。使用javap查看字节码显示,i++是一个多步过程,因此在并发场景下建议使用AtomicInteger确保原子性。通过一个简单的案例和字节码分析,进一步阐述了i++操作的结果为0的原理。
摘要由CSDN通过智能技术生成
一、自增操作的原子性

Java中i++是否是原子的? 答案当然是否定的,java中的自增操作并不是原子的,具体的原因,可以通过查看java字节来了解。

public class Main {
	private int i = 0;
	public  void inc() {
		i++;
	}
}

javap看一下对应的字节码

 0 aload_0  # 载入this指针到当前栈
 1 dup      # 复制栈顶数据
 2 getfield #2 <com/alibaba/rhino/dcc/Main.i> 获取i属性压栈
 5 iconst_1 # 栈顶压栈常量1
 6 iadd     # i在栈内+1后压栈
 7 putfield #2 <com/alibaba/rhino/dcc/Main.i> 把栈顶的值赋值给属性i
10 return

很明显,i++操作过程是多步指令完成的,i++并不是原子操作,因此在开发过程中如果需要原子+/-建议使用AtomicInteger。

二、一个小case

了解的i++是非原子的操作,那么下面来看一个小例子

public class Main {
    public static void main(String[] args) {
        int i = 0;
        i = i++;
        System.out.println(i);
    }
}

输出结果该是怎样的呢? 答案是0
同样的,如果无法理解,可以尝试从字节码的角度来看一下

 0 iconst_0  # 栈顶载入0
 1 istore_1  # 把栈顶的0写入临时变量数组1的位置 -> i=0
 2 iload_1   # 把临时变量区1位置的值压栈,此时栈顶元素值为0
 3 iinc 1 by 1 # 把临时变量去的1+1操作,此时临时变量区的i=1
 6 istore_1   #把栈顶的元素(0)写入到临时变量区1位置 i = 0
 7 getstatic #2 <java/lang/System.out> 
10 iload_1
11 invokevirtual #3 <java/io/PrintStream.println>
14 return

从字节码上来看,最终的结果确实为0。

参考

java bytecode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值