java concurrent atomic
2021年3月21日大约 2 分钟
atomic 包
unsafe 类
- 封装了直接对内存管理、操纵对象、阻塞/唤醒线程等操作
- native 方法,需要通过 CAS 原子指令完成
- 类加载器
Bootstrap类加载器。主要加载的是 JVM 自身需要的类Extension ClassLoader扩展类加载器。负责加载 ext 目录下的类库Application ClassLoader系统类加载器。负责加载用户类路径所指定的类
compareAndSwapInt中的偏移量字段是为了更方便的查找对象
AtomicInteger/AtomicBoolean/AtomicLong 类
三个类只是操作的类型不一样,原理上一致
- 初始化
static {
try {
// value偏移量值的获取
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
- 特殊方法
lazySet。通过共享变量来改变值,与普通操作变量的方式类似。适用于加锁的场景,可以减少不必要的内存屏障
AtomicReference
- 引入类似乐观锁的方式操作共享资源,而非使用锁的方式(悲观)
- 提供了以无锁方式访问共享资源的能力,以自旋和 CAS 的方式来解决共享变量的线程安全问题
- 比较的是对象的引用
class Task implements Runnable {
private AtomicReference<Integer> ref;
Task(AtomicReference<Integer> ref) {
this.ref = ref;
}
@Override
public void run() {
for (; ; ) { //自旋操作
Integer oldV = ref.get();
if (ref.compareAndSet(oldV, oldV + 1)) // CAS操作
break;
}
}
}
AtomicStampedReference
加了版本号的
AtomicReference,可以用来解决 CAS 的 ABA 问题
AtomicMarkableReference
能识别引用变量是否被更改过,使用boolean来标识是否有改过,功能与 AtomicStampedReference 类似
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray
- 以原子的方式操作数组中的元素
- 初始化
static {
// 获取数组中每个元素的占用内存大小
int scale = unsafe.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
// 从最左边起,连续0的个数
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
- 计算公式

LongAddr/(1.8)
- 多线程唤醒下会比 AtomicLong 的吞吐量高,典型的以空间换时间
- 实现思路。分散热点,将 value 值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,减小冲突概率。最后再将值累加起来;只能每次对给定的整数执行一次加法
LongAccumulator。实现思路与LongAddr类似,区别在于可实现任意函数操作- 资料