JAVA原子操作
JAVA的原子操作是由java.util.concurrent.atomic 包提供的。如下:
JAVA类 | 功能描述 |
---|---|
AtomicInteger | 整型原子类 |
AtomicIntegerArray | 整型数组原子类 |
AtomicLong | 长整型原子类 |
AtomicLongArray | 长整型数组原子类 |
AtomicBoolean | 布尔型原子类 |
AtomicReference | 对象原子类 |
AtomicReferenceArray | 对象数组原子类 |
AtomicIntegerFieldUpdater | 反射整型原子类,用于反射机制下的整型原子类的操作 |
AtomicLongFieldUpdater | 反正长整型原子类,用于反射机制下的长整型原子类的操作 |
AtomicStampedReference | 带有标记的原子操作防止ABA问题 |
DoubleAdder | JDK1.8的原子double型操作,优化了高并发下自旋锁的性能瓶颈 |
LongAdder | JDK1.8的原子long型操作 |
DoubleAccumulator | JDK1.8的原子double型通用操作类,优化了高并发下自旋锁的性能瓶颈 |
LongAccumulator | JDK1.8的原子long型通用操作操作 |
JAVA CAS操作实现原理
以AtomicLong和LongAdder的源码为例来看一下如何实现的原子操作。
实现AtomicLong最核心的两个Native方法:
- getLongVolatile(Object obj, long offset) =>根据地址偏移量获取对象的值
- compareAndSwapLong(Object obj, long offset, long expect, long update) =>原子操作进行变量值的更新
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
return var6;
getLongVolatile通过offset获取内存地址的值,然后compareAndSwapLong通过与实际地址的值比较判断,如果相等则将替换成新值,不相等则循环直到成功为止。
该代码通过自旋锁来实现数据的一致性,但是有个问题就是如果高并发的情况下,可能一直循环从而造成一定的cpu时间的浪费,因此在JDK1.8当中提出了LongAdder。
LongAdder新增了cell概念,将数据保存到cell中,通过sum将数据进行整合,优化了高并发出现的资源浪费的问题。如下图
JAVA原子验证
public void add() throws InterruptedException {
for(int i =0;i<1000;i++){
new Thread(()->{
l++;
atomicLong.incrementAndGet();
}).start();
}
Thread.sleep(3000L);
System.out.println("atomicLong : " + atomicLong.get() +" long : " +l);
}
结果:atomicLong : 1000 long : 983