一个比较明显的事实就是 i++
本身不是原子性的,所以在多线程的环境中, i++
会导致最终输出的值不符合我们的预期。
public class AtomicTest {
public static int value = 1;
public static void main(String[] args) {
for (int i = 0; i < 1000000; i++) {
new Thread(AtomicTest::handle).start();
}
}
public static void handle() {
value = value + 1;
System.out.println(value); //>> 我机器输出的结果是999997。
}
}
而AtomicInteger就可以解决在多线程并发的情况下 i++
是原子性的,最终的输出结果是符合我们的预期的。例如上边的代码在我循环100w次的事实输出的结果是999997,而使用 AtomicInteger
进行更新的时候是符合预期的。
AtomicInteger
内部则是使用 unsafe
来进行cas操作。
我们不能直接使用unsafe了,只能通过反射的方式来获取unsafe。然后在来使用它,当然正常情况下我们是用不到的
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
而在unsafe内部,则是使用的死循环的 cas
, 每次都从主内存中获取对应数据,然后比较更新。
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
- getIntVolatile native 实现
- compareAndSwapInt native实现