JUC 包中的 Atomic 原子类总结
🌈个人主页:人不走空
💖系列专栏:算法专题
⏰诗词歌赋:斯是陋室,惟吾德馨
目录
🌈个人主页:人不走空
💖系列专栏:算法专题
⏰诗词歌赋:斯是陋室,惟吾德馨
Atomic 原子类介绍
基本类型原子类
数组类型原子类
引用类型原子类
对象的属性修改类型原子类
作者其他作品:
JavaGuide官方网站:javaguide.cn
Atomic 原子类介绍
Atomic 翻译成中文是“原子”的意思。在化学上,原子是构成物质的最小单位,在化学反应中不可分割。在编程中,Atomic 指的是一个操作具有原子性,即该操作不可分割、不可中断。即使在多个线程同时执行时,该操作要么全部执行完成,要么不执行,不会被其他线程看到部分完成的状态。
原子类简单来说就是具有原子性操作特征的类。
java.util.concurrent.atomic 包中的 Atomic 原子类提供了一种线程安全的方式来操作单个变量。
Atomic 类依赖于 CAS(Compare-And-Swap,比较并交换)乐观锁来保证其方法的原子性,而不需要使用传统的锁机制(如 synchronized 块或 ReentrantLock)。
这篇文章我们只介绍 Atomic 原子类的概念,具体实现原理可以阅读笔者写的这篇文章:什么是乐观锁和悲观锁?Java 中 CAS 是如何实现的?。
JUC原子类概览
根据操作的数据类型,可以将 JUC 包中的原子类分为 4 类:
1、基本类型
使用原子的方式更新基本类型
-
AtomicInteger:整型原子类
-
AtomicLong:长整型原子类
-
AtomicBoolean:布尔型原子类
2、数组类型
使用原子的方式更新数组里的某个元素
-
AtomicIntegerArray:整型数组原子类
-
AtomicLongArray:长整型数组原子类
-
AtomicReferenceArray:引用类型数组原子类
3、引用类型
-
AtomicReference:引用类型原子类
-
AtomicMarkableReference:原子更新带有标记的引用类型。该类将 boolean 标记与引用关联起来,也可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
-
AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
🐛 修正(参见:issue#626:https://github.com/Snailclimb/JavaGuide/issues/626) : AtomicMarkableReference 不能解决 ABA 问题。
4、对象的属性修改类型
-
AtomicIntegerFieldUpdater:原子更新整型字段的更新器
-
AtomicLongFieldUpdater:原子更新长整型字段的更新器
-
AtomicReferenceFieldUpdater:原子更新引用类型里的字段
基本类型原子类
使用原子的方式更新基本类型
-
AtomicInteger:整型原子类
-
AtomicLong:长整型原子类
-
AtomicBoolean:布尔型原子类
上面三个类提供的方法几乎相同,所以我们这里以 AtomicInteger 为例子来介绍。
AtomicInteger 类常用方法 :
public final int get() //获取当前的值 public final int getAndSet(int newValue)//获取当前的值,并设置新的值 public final int getAndIncrement()//获取当前的值,并自增 public final int getAndDecrement() //获取当前的值,并自减 public final int getAndAdd(int delta) //获取当前的值,并加上预期的值 boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update) public final void lazySet(int newValue)//最终设置为newValue, lazySet 提供了一种比 set 方法更弱的语义,可能导致其他线程在之后的一小段时间内还是可以读到旧的值,但可能更高效。
AtomicInteger 类使用示例 :
// 初始化 AtomicInteger 对象,初始值为 0 AtomicInteger atomicInt = new AtomicInteger(0); // 使用 getAndSet 方法获取当前值,并设置新值为 3 int tempValue = atomicInt.getAndSet(3); System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt); // 使用 getAndIncrement 方法获取当前值,并自增 1 tempValue = atomicInt.getAndIncrement(); System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt); // 使用 getAndAdd 方法获取当前值,并增加指定值 5 tempValue = atomicInt.getAndAdd(5); System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt); // 使用 compareAndSet 方法进行原子性条件更新,期望值为 9,更新值为 10 boolean updateSuccess = atomicInt.compareAndSet(9, 10); System.out.println("Update Success: " + updateSuccess + "; atomicInt: " + atomicInt); // 获取当前值 int currentValue = atomicInt.get(); System.out.println("Current value: " + currentValue); // 使用 lazySet 方法设置新值为 15 atomicInt.lazySet(15); System.out.println("After lazySet, atomicInt: " + atomicInt);
输出:
tempValue: 0; atomicInt: 3 tempValue: 3; atomicInt: 4 tempValue: 4; atomicInt: 9 Update Success: true; atomicInt: 10 Current value: 10 After lazySet, atomicInt: 15
数组类型原子类
使用原子的方式更新数组里的某个元素
-
AtomicIntegerArray:整形数组原子类
-
AtomicLongArray:长整形数组原子类
-
AtomicReferenceArray:引用类型数组原子类
上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerArray 为例子来介绍。
AtomicIntegerArray 类常用方法:
public final int get(int i) //获取 index=i 位置元素的值 public final int getAndSet(int i, int newValue)//返回 index=i 位置的当前的值,并将其设置为新值:newValue public final int getAndIncrement(int i)//获取 index=i 位置元素的值,并让该位置的元素自增 public final int getAndDecrement(int i) //获取 index=i 位置元素的值,并让该位置的元素自减 public final int getAndAdd(int i, int delta) //获取 index=i 位置元素的值,并加上预期的值 boolean compareAndSet(int i, int expect, int update) //如果输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update) public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
AtomicIntegerArray 类使用示例 :
int[] nums = {1, 2, 3, 4, 5, 6}; // 创建 AtomicIntegerArray AtomicIntegerArray atomicArray = new AtomicIntegerArray(nums); // 打印 AtomicIntegerArray 中的初始值 System.out.println("Initial values in AtomicIntegerArray:"); for (int j = 0; j
-
-
-
-
-