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 操作,在不使用传统锁的情况下实现了原子操作,提高了并发性能。