Java基础-基础语法-JVM执行自增运算的原理

Java工程师知识树 / Java基础
题目:下面代码执行后输入结果为?

public static void main(String[] args) { int ct = 0; for (int i = 0; i < 100; i++) { ct++; } System.out.println("ct:"+ct); int count = 0; for (int i = 0; i < 100; i++) { count = count++; } System.out.println("count:"+count); int size = 0; for (int i = 0; i < 100; i++) { size = ++size; } System.out.println("size:"+size); }

答案为

ct:100 count:0 size:100

解析:

  • 1.通过ct与count,可以得到在java等语言中 count = count++ 与 count++ 是不等效的
  • 2.通过size与count,可以得到i++和++i的运行原理是不一样的
i++和++i的区别通过字节码查看一下
Java基础-基础语法-JVM执行自增运算的原理
文章图片
image.png
public static void main(String[] args) { int count = 0; count = count++; }

源代码解析出的字节码
public static void main(java.lang.String[]); Code: 0: iconst_0 1: istore_1 2: iload_1// 把局部变量1的值放到栈顶,此时栈顶的值变为0 3: iinc1, 1//局部变量1加1变为1,注意这时栈中仍然是0,没有改变 6: istore_1//把栈顶的值放到局部变量1中,即局部变量1这时候值还是0 7: return }

public static void main(String[] args) { int count = 0; count = ++count; }

【Java基础-基础语法-JVM执行自增运算的原理】源代码解析出的字节码
public static void main(java.lang.String[]); Code: 0: iconst_0 1: istore_1 2: iinc1, 1//局部变量1加1变为1,注意这时栈中仍然是0,没有改变 5: iload_1// 把局部变量1的值放到栈顶,此时栈顶的值变为1 6: istore_1//把栈顶的值放到局部变量1中,即局部变量1这时候由0变成了1 7: return }

上面题目答案解读:

count = count++;java虚拟机执行时是这样的: count的值加了1,但这时栈中的值还是0, 而后"="赋值操作又将栈中的值覆盖count,即count变成0,因此不管循环多少次,count都等于0。
而size = ++size; java虚拟机执行时是这样的: 栈中的值加了1,这时size的值还是0, 而后"="赋值操作将栈中的值覆盖size,即size变成1,完成一次循环后size值是加1的,所以执行完循环后,size值就是100了。
延伸问题: 可以通过哪些方式来保证并发安全的自增自减操作?
答:java 默认的自增自减运算符是非并发安全的,要想实现并发安全的自增自减操作可以通过如下几种方式实现:
  • 通过 synchronized 代码块或者方法来保证自增自减并发安全。
  • 通过主动使用 Lock 锁来保证自增自减并发安全。
  • 通过 JDK 提供的 AtomicInteger 类来直接保证自增自减并发安全。
上面几种做法中最推荐直接使用 AtomicInteger 的方式,因为其相对于其他几种方式封装性非常便捷,此外其实现基于 volatile 对象的 CAS 操作来保证并发安全,算是一种相对高效的方式。

    推荐阅读