Java原子类简述
一、概述
java的java.util.concurrent包除了提供底层锁、并发集合外,还提供了一组原子操作的封装类,它们位于java.util.concurrent.atomic包。
Atomic类是通过无锁(lock-free)的方式实现的线程安全(thread-safe)访问
二、原子类是基于什么实现的
原子类的实现是基于CPU本身提供的CAS指令,是一种无锁的实现;
CAS(Compare and Swap)比较并交换,即在更新之前会校验是否于期待的值相等
执行函数:CAS(V,E,N)
V表示要更新的变量;E表示预期值;N表示新值
CAS容易出现ABA问题
容易出现在原子变量值不确定容易反复的情况
假设count原本是A,线程1检查数值 期望值为A,未执行更新操作,此时线程2更新值为B,线程3更新值为A,然后线程1执行更新操作 ,期望值与实际值相同执行操作。
解决方案:类似乐观锁,加上版本号。
三、常用的原子类
1. 基本类型
使用原子的方式更新基本类型
| 原子类 | 类型 |
|---|---|
| 整形原子类 | |
| AtomicLong | 长整型原子类 |
| AtomicBoolean | 布尔型原子类 |
2. 引用类型
| 原子类 | 类型 |
|---|---|
| 引用类型原子类 | |
| 原子更新引用类型里的字段原子类 | |
| 原子更新带有标记位的引用类型 |
ABA 问题
AtomicStampedReference和AtomicMarkableReference这两个原子类可以解决ABA问题。
AtomicStampedReference该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。
3. 数组类型
| 原子类 | 类型 |
|---|---|
| 整形数组原子类 | |
| AtomicLongArray | 长整形数组原子类 |
| AtomicReferenceArray | 引用类型数组原子类 |
这些类提供的方法和原子化的基本数据类型 的区别仅仅是:每个方法多了一个数组的索引参数,所以这里也不再赘述了。
4. 对象属性更新器
| 原子类 | 类型 |
|---|---|
| AtomicIntegerFieldUpdater | 原子更新整形的更新器 |
| AtomicLongFieldUpdater | 原子更新长整形的更新器 |
| 原子更新引用的更新器 |
利用它们可以原子化地更新对象的属性,这三个方法都是利用反射机制实现的。
5. 累加器
| 原子类 | 类型 |
|---|---|
| DoubleAccumulator | 原子更新整形字段的更新器 |
| DoubleAdder | 原子更新长整形字段的更新器 |
| LongAccumulator | 原子更新长整形字段的更新器 |
| 原子更新长整形字段的更新器 |
LongAccumulator是LongAdder的功能增强版,LongAdder的API只有对数值的加减,而LongAccumulator提供了自定义的函数操作。
这四个类仅仅用来执行累加操作,相比原子化的基本数据类型,速度更快,但是不支持compareAndSet()方法。如果仅仅需要累加操作,使用原子化的累加器性能会更好
四、原子类的用途
适用于计数器,累加器等场景(更推荐redis)
参考文章
- 原子类