从JDK1.5开始,Java为我们提供的一系列的原子处理类:AtomicBoolean、AtomicInteger、AtomicLong等等,主要用在高并发的场景下高效处理程序,为我们简化同步处理。
我们以AtomicInteger举例:
AtomicInteger是一个提供原子操作的Integer类,在Java中,++i和i++并不是线程安全的,在使用的时候我们不可避免的使用synchronized关键字进行加锁操作。但是AtomicInteger则提供了一种线程安全的操作接口:
public final int get() //获取当前的值
public final int getAndSet(int newValue) //获取当前的值,并设置新的值
public final int getAndIncrement() //获取当前的值,并自增
public final int getAndDecrement() //获取当前的值,并自减
public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
使用了AtomicInteger之后,我们就没有必要给数值的操作加锁了,这样在非激烈竞争的情况下,开销更小,速度更快。
AtomicInteger本质上是通过CAS实现的,它里面主要维护了三个变量:
- unSafe:Java提供的获得对对象内存地址访问的类
- valueOffset:value本身在内存地址的偏移量,为了方便找到保存数据的地址,方便进行比较
- value:存储的值,该属性借助volatile保证其在线程间是可见的
我们查看AtomicInteger的自增函数incrementAndGet()的源码时,发现自增函数底层调用的是unsafe.getAndAddInt()。
// ------------------------- JDK 8 -------------------------
// AtomicInteger 自增方法
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
// Unsafe.class
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;
}
// ------------------------- OpenJDK 8 -------------------------
// Unsafe.java
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
getAndAddInt()循环获取给定对象o中的偏移量处的值v,然后判断内存值是否等于v。如果相等则将内存值设置为 v + delta,否则返回false,继续循环进行重试,直到设置成功才能退出循环,并且将旧值返回。整个“比较+更新”操作封装在compareAndSwapInt()中,在JNI里是借助于一个CPU指令完成的,属于原子操作,可以保证多个线程都能够看到同一个变量的修改值。