Java Atomic 原子类介绍
什么是 Atomic?
Atomic 翻译成中文是“原子”。在化学上,原子是构成物质的最小单位,不可分割。在编程中,Atomic 表示一个操作具有原子性,即该操作不可分割、不可中断。在多线程环境中,操作要么完全执行完毕,要么完全未执行,不会被其他线程看到中间状态。
原子类 是具有原子性操作特性的类。
Java 提供了 java.util.concurrent.atomic
包,其中的原子类利用 CAS(Compare-And-Swap,比较并交换) 乐观锁机制来实现线程安全的操作,而无需使用传统的锁(如 synchronized
或 ReentrantLock
)。
JUC 原子类概览
根据操作的数据类型,JUC 包中的原子类分为四类:
1. 基本类型
原子更新基本类型:
- AtomicInteger:整型原子类
- AtomicLong:长整型原子类
- AtomicBoolean:布尔型原子类
2. 数组类型
原子更新数组中的元素:
- AtomicIntegerArray:整型数组原子类
- AtomicLongArray:长整型数组原子类
- AtomicReferenceArray:引用类型数组原子类
3. 引用类型
原子更新引用类型:
- AtomicReference:引用类型原子类
- AtomicMarkableReference:带标记的引用类型,结合 boolean 标记解决 CAS 可能引发的 ABA 问题。
- AtomicStampedReference:带版本号的引用类型,解决 ABA 问题。
4. 对象属性更新类型
原子更新对象的某些属性:
- AtomicIntegerFieldUpdater:更新整型字段
- AtomicLongFieldUpdater:更新长整型字段
- AtomicReferenceFieldUpdater:更新引用类型字段
基本类型原子类
常用方法
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 atomicInt = new AtomicInteger(0);
// 获取当前值并设置为新值
int tempValue = atomicInt.getAndSet(3);
System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt);
// 获取当前值并自增
tempValue = atomicInt.getAndIncrement();
System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt);
// 获取当前值并加上指定值
tempValue = atomicInt.getAndAdd(5);
System.out.println("tempValue: " + tempValue + "; atomicInt: " + atomicInt);
// 比较并更新
boolean updateSuccess = atomicInt.compareAndSet(9, 10);
System.out.println("Update Success: " + updateSuccess + "; atomicInt: " + atomicInt);
// 设置新值(延迟)
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
After lazySet, atomicInt: 15
数组类型原子类
常用方法
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};
AtomicIntegerArray atomicArray = new AtomicIntegerArray(nums);
// 获取某个索引的值
System.out.println("Index 0: " + atomicArray.get(0));
// 设置新值并返回旧值
int tempValue = atomicArray.getAndSet(0, 2);
System.out.println("After getAndSet(0, 2): " + atomicArray.get(0));
// 自增某个索引的值
tempValue = atomicArray.getAndIncrement(0);
System.out.println("After getAndIncrement(0): " + atomicArray.get(0));
输出:
Index 0: 1
After getAndSet(0, 2): 2
After getAndIncrement(0): 3
引用类型原子类
1. AtomicReference
AtomicReference<Person> ar = new AtomicReference<>(new Person("Alice", 25));
// 更新引用
Person updatedPerson = new Person("Bob", 30);
ar.compareAndSet(ar.get(), updatedPerson);
System.out.println("Updated Person: " + ar.get());
2. AtomicStampedReference
AtomicStampedReference<String> asr = new AtomicStampedReference<>("Alice", 1);
// 获取当前值和版本号
int[] stamp = new int[1];
String currentRef = asr.get(stamp);
System.out.println("Current Value: " + currentRef + ", Stamp: " + stamp[0]);
// 更新值和版本号
boolean success = asr.compareAndSet("Alice", "Bob", stamp[0], stamp[0] + 1);
System.out.println("Update Success: " + success);
对象属性修改类型原子类
以 AtomicIntegerFieldUpdater
为例:
class Person {
volatile int age;
Person(int age) { this.age = age; }
}
AtomicIntegerFieldUpdater<Person> ageUpdater =
AtomicIntegerFieldUpdater.newUpdater(Person.class, "age");
Person person = new Person(20);
ageUpdater.incrementAndGet(person);
System.out.println("Updated Age: " + person.age);
输出:
Updated Age: 21
总结
Java 中的 Atomic 类提供了一种轻量级的线程安全方案,避免了锁带来的性能开销。根据实际需求,选择合适的原子类可以提高多线程程序的效率。
评论区