1. 原子操作的定义
在 Java 并发编程里,原子操作指的是不可被中断的一个或一系列操作。也就是说,在执行过程中,不会被其他线程干扰,要么全部执行完成,要么完全不执行,不会出现执行到一半被其他线程插入操作的情况。原子操作是并发编程中的基础,能保证数据在多线程环境下的一致性和完整性。
2. 可用的原子类
Java 在 java.util.concurrent.atomic
包中提供了一系列原子类,常见的原子类可以分为以下几类:
2.1 基本类型原子类
AtomicInteger
:用于对int
类型变量进行原子操作。AtomicLong
:用于对long
类型变量进行原子操作。AtomicBoolean
:用于对boolean
类型变量进行原子操作。
2.2 数组类型原子类
AtomicIntegerArray
:用于对int
类型数组元素进行原子操作。AtomicLongArray
:用于对long
类型数组元素进行原子操作。AtomicReferenceArray
:用于对引用类型数组元素进行原子操作。
2.3 引用类型原子类
AtomicReference
:用于对引用类型进行原子操作。AtomicStampedReference
:带有版本号的引用类型原子类,可解决 ABA 问题。AtomicMarkableReference
:带有标记位的引用类型原子类。
2.4 字段更新器原子类
AtomicIntegerFieldUpdater
:用于对int
类型的字段进行原子更新。AtomicLongFieldUpdater
:用于对long
类型的字段进行原子更新。AtomicReferenceFieldUpdater
:用于对引用类型的字段进行原子更新。
3. 原子类实现原子性的原理
Java 中的原子类主要借助 Unsafe
类和 CAS(Compare-And-Swap,比较并交换)操作来实现原子性。
3.1 Unsafe
类
Unsafe
类是 Java 提供的一个特殊类,它提供了一些底层操作,如直接访问内存、操作内存地址等。原子类通过 Unsafe
类来直接操作内存中的变量,从而避免了传统锁机制带来的性能开销。
3.2 CAS 操作
CAS 操作是一种乐观锁机制,包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。当且仅当内存位置 V 的值等于预期原值 A 时,才会将内存位置 V 的值更新为新值 B;否则,不做任何操作。整个操作是原子性的,由 CPU 硬件指令保证。
以 AtomicInteger
类的 getAndIncrement()
方法为例,其源码实现如下:
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
getAndAddInt()
方法的具体实现如下:
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
getIntVolatile(o, offset)
:从内存中获取对象o
偏移量为offset
处的int
类型的值。compareAndSwapInt(o, offset, v, v + delta)
:使用 CAS 操作尝试将对象o
偏移量为offset
处的值从v
更新为v + delta
。如果更新成功,返回true
;否则返回false
。- 通过
do-while
循环不断尝试,直到 CAS 操作成功,从而保证了getAndIncrement()
方法的原子性。
综上所述,Java 原子类利用 Unsafe
类和 CAS 操作,在不使用传统锁的情况下实现了原子操作,提高了并发性能。