首先看个问题
题目:下面代码执行后输入结果为?
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的区别通过字节码查看一下
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: iinc 1, 1 //局部变量1加1变为1,注意这时栈中仍然是0,没有改变
6: istore_1 //把栈顶的值放到局部变量1中,即局部变量1这时候值还是0
7: return
}
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: iinc 1, 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 操作来保证并发安全,算是一种相对高效的方式。