(java.util.concurrent.atomic 包)提供了一种无锁、线程安全的方式来操作共享变量,底层基于 CAS(Compare and Swap) 机制实现。它们适用于高并发场景下的简单原子操作,避免了传统锁机制的性能开销。主要作用如下:
- 线程安全:保证对变量的操作在多线程环境下是原子的。
- 高性能:通过 CAS 无锁机制减少线程阻塞和上下文切换。
- 简化代码:避免显式使用
synchronized或Lock。
一、基本类型原子类
1. AtomicBoolean
• 特性:原子更新布尔值。 • 实现原理:内部通过volatile int value存储状态(0表示false,1表示true),使用Unsafe类的CAS操作保证原子性。 • 核心方法:
public final boolean compareAndSet(boolean expect, boolean update);
2. AtomicInteger
• 特性:原子更新整型值。 • 实现原理:内部维护volatile int value,通过Unsafe的CAS操作(如getAndAddInt)实现原子增减。 • 典型方法:
public final int incrementAndGet(); // 原子自增
public final int getAndAdd(int delta); // 原子加delta
3. AtomicLong
• 特性:原子更新长整型值。 • 实现原理:与AtomicInteger类似,使用volatile long value和Unsafe的CAS操作。 • 适用场景:高并发计数器(如统计请求次数)。
二、引用类型原子类
4. AtomicReference
• 特性:原子更新对象引用。 • 实现原理:通过volatile V value和Unsafe的compareAndSwapObject实现引用替换。 • 示例:
AtomicReference<String> ref = new AtomicReference<>("initial");
ref.compareAndSet("initial", "updated"); // 原子更新引用
5. AtomicStampedReference
• 特性:原子更新引用,并解决ABA问题(通过版本戳)。 • 实现原理:维护一个Pair对象,包含引用和int类型的版本戳。
public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp);
6. AtomicMarkableReference
• 特性:通过布尔标记解决ABA问题(无需版本号)。 • 实现原理:维护一个Pair对象,包含引用和boolean标记。
public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark);
三、数组类型原子类
7. AtomicIntegerArray
• 特性:原子更新整型数组中的元素。 • 实现原理:内部维护int[] array,通过Unsafe的getAndAddInt操作原子更新指定索引的值。
public final int getAndAdd(int i, int delta);
8. AtomicLongArray
• 特性:原子更新长整型数组中的元素。 • 实现原理:与AtomicIntegerArray类似,针对long类型。
9. AtomicReferenceArray
• 特性:原子更新对象引用数组中的元素。 • 实现原理:通过Unsafe的compareAndSwapObject实现数组元素的原子替换。
四、字段更新器
10. AtomicIntegerFieldUpdater
• 特性:原子更新对象的volatile int字段。 • 实现原理:通过反射获取字段的偏移量,使用Unsafe的CAS操作。 • 示例:
public class Counter {
private volatile int count;
}
AtomicIntegerFieldUpdater<Counter> updater =
AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");
updater.getAndIncrement(counter); // 原子递增
11. AtomicLongFieldUpdater
• 特性:原子更新对象的volatile long字段。 • 实现原理:类似AtomicIntegerFieldUpdater,针对long类型。
12. AtomicReferenceFieldUpdater
• 特性:原子更新对象的volatile引用字段。 • 实现原理:通过反射和Unsafe的CAS操作替换引用。
AtomicReferenceFieldUpdater<User, String> updater =
AtomicReferenceFieldUpdater.newUpdater(User.class, String.class, "name");
五、高性能累加器
13. LongAdder / DoubleAdder
• 特性:高并发下比AtomicLong更高的吞吐量,适用于频繁更新但较少读取的场景。 • 实现原理:采用分段累加(Cell数组),减少线程竞争。
LongAdder adder = new LongAdder();
adder.add(1); // 分段累加
long sum = adder.sum(); // 合并所有分段的值
14. LongAccumulator / DoubleAccumulator
• 特性:支持自定义累加函数(如最大值、最小值)。 • 实现原理:类似LongAdder,但允许指定累加规则。
LongAccumulator maxAccumulator = new LongAccumulator(Long::max, 0);
maxAccumulator.accumulate(10); // 更新当前最大值
六、实现原理的核心技术
-
CAS(Compare-And-Swap) • 通过
Unsafe类提供的底层CAS方法(如compareAndSwapInt)实现无锁更新。 • 示例:AtomicInteger的自增操作:public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } -
Volatile变量 • 所有原子类的值均通过
volatile修饰,保证可见性。 • 如AtomicInteger中的private volatile int value。 -
分段累加(LongAdder) • 将单个变量拆分为多个Cell,线程竞争时分散到不同Cell。 • 最终结果通过合并所有Cell的值获得。
七、ABA 问题及解决方案
1. ABA 问题
- 现象:变量从
A改为B后又改回A,CAS 无法感知中间变化。 - 风险:可能导致数据一致性问题(如链表节点的中途修改)。
2. 解决方案
AtomicStampedReference:通过版本号(int stamp)标记状态。AtomicMarkableReference:通过布尔标记(boolean mark)简化版本控制。
示例:
java
复制
AtomicStampedReference<String> stampedRef =
new AtomicStampedReference<>("A", 1);
int oldStamp = stampedRef.getStamp();
stampedRef.compareAndSet("A", "B", oldStamp, oldStamp + 1); // 更新值和版本号
八、适用场景对比
| 原子类 | 适用场景 |
|---|---|
| AtomicInteger/Long | 低竞争环境下的计数器(如简单统计)。 |
| LongAdder | 高并发写入、低频读取(如QPS统计)。 |
| AtomicReference | 原子更新对象引用(如单例模式的双重检查锁)。 |
| AtomicStampedReference | 需解决ABA问题的场景(如无锁栈/队列)。 |
| AtomicIntegerArray | 原子更新数组元素(如并行计算中的分片统计)。 |
九、总结
Java的原子类通过CAS和volatile变量实现无锁线程安全,适用于计数器、状态标志、对象引用更新等场景。针对不同需求,选择合适类型的原子类: • 基本类型:AtomicInteger、AtomicLong。 • 引用类型:AtomicReference、AtomicStampedReference。 • 高并发累加:LongAdder、LongAccumulator。 • 字段更新:AtomicIntegerFieldUpdater。
理解其底层实现(如CAS、分段累加)有助于优化高并发程序的性能和可靠性。