原子类
为了解决数据修改的原子性,Java5引进了原子类,原子类使用volatile保证了内存可见性,使用CAS算法保证了原子性。
- 基本类型: AtomicInteger, AtomicLong, AtomicBoolean
- 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray
- 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference
AtomicStampedReference是使用int类型的版本号解决ABA问题。
AtomicMarkableReference是使用一个boolean类型的标记解决ABA问题。 - 对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater
public class Data {
private volatile int num;
public static void main(String[] args) {
/**
* 必须是volatile类型
* 只能是 int 不能是 Integer
* 不能加 static、final修饰
* 无法操作父类的字段
*/
AtomicIntegerFieldUpdater<Data> test =
AtomicIntegerFieldUpdater.newUpdater(Data.class, "num");
Data data = new Data();
data.num = 0;
test.addAndGet(data, 1);
System.out.println(data.num);
}
}
- JDK1.8新增:DoubleAccumulator、LongAccumulator、DoubleAdder、LongAdder
AtomicLong在高并发场景下,多个线程竞争修改共享资源value,CAS算法中循环耗时过长,性能问题严重,所以引入了Adder和Accumulator2个类。它们都继承了Striped64类,它里面定义了一个Cell[]数组,核心原理就是当有多个线程都试图修改当前的value的时候,如果能够通过CAS修改成功,那么直接退出(并发里量不大),否则去cells里面占一个非空的位置(并发量大),并把要操作的值赋值保存在一个Cell里面,最后可以计算总数。
Addr与Accumulator类都是使用非阻塞算法CAS实现的,Accumulator可以让用户自定义累加规则,Adder类是Accumulator类的一个特例只是简单的加法。
public static void main(String[] args) {
LongAdder longAdder = new LongAdder();
longAdder.add(1);
longAdder.add(2);
long sum = longAdder.sum();//3
LongBinaryOperator longBinaryOperator = (a, b) -> a * b;
LongAccumulator longAccumulator = new LongAccumulator(longBinaryOperator, 3);
longAccumulator.accumulate(2);
long l = longAccumulator.get();//6
}
对于DoubleAdder和DoubleAccumulator,则是将其转化为long类型后进行运算的。
//long转为double
public static native double longBitsToDouble(long bits);
//double转为long
public static native long doubleToRawLongBits(double value);