Atomic
原子操作更新基本类型
AtomicBoolean:原子更新布尔类型
AtomicInteger:原子更新整形
AtomicLong:原子更新长整形
原子操作更新数组
AtomicIntegerArray: 原子更新整形数据里的元素
AtomicLongArray: 原子更新长整形数组里的元素
AtomicReferenceArray: 原子更新饮用类型数组里的元素
AtomicIntegerArray: 主要提供原子方式更新数组里的整形
原子操作更新引用类型
如果原子需要更新多个变量,就需要用引用类型了。
AtomicReference : 原子更新引用类型
- AtomicStampedReference:带版本戳的原子引用类型,版本戳为int类型。
- AtomicMarkableReference:带版本戳的原子引用类型,版本戳为boolean类型。
AtomicStampedReference 通过引入“版本”的概念,来解决 CAS ABA 问题
AtomicMarkableReference: 原子更新带有boolean标记位(是上面版本的简化,不关心修改几次)的引用类型。
|
|
字段原子更新器
AtomicIntegerFieldUpdater: 原子更新整形字段的更新器
AtomicLongFieldUpdater: 原子更新长整形字段的更新器
AtomicReferenceFieldUpdater: 原子更新引用类型里的字段。
AtomicIntegerFieldUpdater原子类的使用场景最主要的就是可以不用修改过多的代码就可以保证代码的原子性操作!
- 变量必须使用volatile关键字修饰。使用volatile是为了保证可见性,如果没有volatile关键字修饰,使用newUpdater()会抛出IllegalArgumentException异常。
- 不能使用static关键字。
- 不能使用final关键字。
- 变量的描述符类型必须与调用者一致。如果调用者能够调用变量就能够通过反射操作保证原子性。
|
|
LongAdder DoubleAdder
- 类似于 count++ 这种非一写多读的场景不能使用 volatile;
- 如果是 JDK8 推荐使用 LongAdder 而非 AtomicLong 来替代 volatile,因为 LongAdder (减少乐观锁的重试次数)的性能更好。
在低竞争的并发环境下 AtomicInteger 的性能是要比 LongAdder 的性能好,而高竞争环境下 LongAdder 的性能比 AtomicInteger 好,当有 1000 个线程运行时,LongAdder 的性能比 AtomicInteger 快了约 1.53 倍,所以各位要根据自己业务情况选择合适的类型来使用。
因为 AtomicInteger 在高并发环境下会有多个线程去竞争一个原子变量,而始终只有一个线程能竞争成功,而其他线程会一直通过 CAS 自旋尝试获取此原子变量,因此会有一定的性能消耗;而 LongAdder 会将这个原子变量分离成一个 Cell 数组,每个线程通过 Hash 获取到自己数组,这样就减少了乐观锁的重试次数,从而在高竞争下获得优势;而在低竞争下表现的又不是很好,可能是因为自己本身机制的执行时间大于了锁竞争的自旋时间,因此在低竞争下表现性能不如 AtomicInteger。
LongAccumulator DoubleAccumulator
LongAdder这个类也有点局限性,因为只能是每一次都+1,那有没有办法每次+2呢?或者每次乘以2?LongAccumulator这个累加器,这个累加器更加抽象,前面使用的LongAdder只不过是这个累加器的一个特例。
|
|