JUC: AtomicXXX
使用
JDK在 java.util.concurrent.atomic 下提供了一系列AtomicXX类型,这些类型提供了一系列原子方法,可以避免线程安全问题。下面是AtomicInteger的使用方式:
AtomicInteger i = new AtomicInteger(10);
i.incrementAndGet(); // 多个线程同时增加,不会造成线程安全问题原理
Atomic类型皆是使用CAS(CompareAndSwap)来实现的。在java中,compareAndSwap也是一个方法,位于UnSafe类中:
// AtomicInteger#incrementAndGet
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1; // 给对象this的valueOffset属性+1
}// UnSafe#getAndAddInt
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)); // 如果不是期望值(var5仍是当前值,说明没有被其他线程修改),返回false,如果是期望值则设置为 var5+1 目标值
return var5;
}CAS需要CPU原语支持,也称为无锁优化,自旋锁。
ABA问题
使用CAS进行无锁优化时,有可能引发ABA问题:
变量A不见得是数值,也有可能是对象。对象引用虽然不变,但是成员变量可能已经发生变化。
通俗点说就是,你的前女友在和你复合之后,看似和以前没有区别,但是其实已经经历了n个男人,这就是ABA问题。ABA问题针对简单数字增减一般是不会出现问题,是允许的;但是针对其他对象操作,就有可能发生问题。
解决ABA问题
解决ABA问题最容易想到的办法就是给变量增加版本号,JDK已经了类 AtomicStampedReference 类解决ABA问题:
LongAdder
此外,在 java.util.concurrent.atomic 下还包含XXXAdder类,以LongAdder为例:
LongAdder采用分段锁,这使得LongAdder的效率高于synchronized、Atomic。
最后更新于
这有帮助吗?