目录
3.4.1 AtomicIntegerFieldUpdater
3.4.3 AtomicReferenceFieldUpdater
1 原子操作
假定有两个操作 A 和 B,如果从执行 A 的线程来看,当另一个线程执行 B 时,要么将 B全部执行完,要么完全不执行 B,执行 B 的线程看 A 的操作也是一样的,那么 A和 B 对彼此来说是原子的
synchronized 关键字是基于阻塞的锁机制,但有几个问题:
阻塞的线程优先级很高
锁的线程一直不释放锁
死锁之类的情况
锁机制是一种粒度比较大的机制
为了解决这个问题,Java 提供了 Atomic 系列的原子操作类
2 CAS 实现原子操作的三大问题
2.1 ABA问题
如果一个值原来是 A,变成了 B,又变成了 A
ABA 问题的解决思路就是使用版本号 A→B→A 就会变成 1A→2B→3A
2.2 循环时间长开销大
自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销
2.3 仅能保证一个共享变量的原子操作
多个共享变量操作时,循环 CAS 就无法保证操作的原子性
如:共享变量 i=2,j=3,通过CAS分别操作i j,可能会引发问题;解决:加锁,将ij绑在一起操作;JDK 提供了 AtomicReference 类来保证引用对象之间的原子性,可以将多个变量放对象里操作
3 Jdk 中相关原子操作类
3.1 AtomicInteger
int addAndGet(int delta):原子相加
boolean compareAndSet(int expect,int update):输入的数值等于预期值,就进行原子赋值
int getAndIncrement():原子方式将当前值加 1,返回自增前的值
nt getAndSet(int newValue):原子方式设置为 newValue 的值返回旧值
3.2 AtomicIntegerArray
原子的方式更新数组里的整型
int addAndGet(int i,int delta):原子方式执行 数组i值+delta
boolean compareAndSet(int i,int expect,int update):如果当前值=expect,则将数组i值=update
AtomicIntegerArray会将数组复制一份,当AtomicIntegerArray对内部值进行修改时,不会影响原数组
3.3 更新引用类型
3.3.4 AtomicReference
原子更新引用类型
3.3.5 AtomicStampedReference
利用版本戳的形式记录了每次改变以后的版本号,这样就不会存在ABA问题
3.3.6 AtomicMarkableReference
原子更新带有标记位的引用类型
3.4 原子更新字段类
3.4.1 AtomicIntegerFieldUpdater
原子更新整型字段
3.4.2 AtomicLongFieldUpdater
原子更新长整型字段
3.4.3 AtomicReferenceFieldUpdater
原子更新引用类型字段
3.5 LongAdder
AtomicLong利用底层CAS操作提供并发性,调用unsafe.getAndAddLong方法(采用自旋方式不断更新目标值,直到更新成功)
为了解决高并发环境下AtomicLong的自旋瓶颈问题
采取思想:自增场景下,将对value的热点操作进行分散,记录每个线程对value的操作到arr中,最后进行累加
线程数越多,并发操作数越大,LongAdder的性能越优;线程数较小,AtomicLong操作更优
3.6 其它新增
3.6.1 LongAccumulator
LongAdder的增强版,LongAdder仅提供数值加减,LongAccumulator提供自定义函数
3.6.2 DoubleAdder
Double类型的累加原子操作
3.6.3 DoubleAccumulator
Double类型的累加原子操作,支持自定义函数