多线程(35)原子类

134 阅读2分钟

什么是原子操作?

原子操作(Atomic Operations)是在多线程环境中执行时不会被线程调度机制打断的操作;这类操作一旦开始,就会一直运行到结束,中间不会出现上下文切换,从而保证了操作的完整性。在并发编程中,原子操作往往是必须的,以保证数据的一致性和完整性。

在计算机科学中,原子性意味着一个操作或者一系列操作是不可分割的,即要么全部完成要么全部不做,不会停留在中间某个步骤。这在多线程环境中尤其重要,原子性操作可以防止其他线程看到不一致的数据状态。

Java中的原子类

Java中的原子操作主要由java.util.concurrent.atomic包提供的类来实现。这些类利用了底层的CAS(Compare-And-Swap)操作来保证操作的原子性。CAS操作是处理器提供的一种原子性指令,用于在并发算法中实现无锁的线程安全编程。

以下是一些常用的Java原子类:

  • AtomicBoolean:一个布尔值,可以原子地更新。
  • AtomicInteger:一个整数值,可以原子地更新。
  • AtomicLong:一个长整型数值,可以原子地更新。
  • AtomicReference:一个对象引用,可以原子地更新。
  • 数组类型:如AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray,它们分别提供了原子更新数组中的元素。
  • 字段更新器:如AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater,它们提供了原子更新对象的字段。
  • AtomicStampedReference:一个带有整数标记的对象引用,可以用于解决CAS操作中的ABA问题。

源码解析

AtomicInteger为例,来看看Java如何实现原子操作。AtomicInteger类的部分关键源码如下:

public class AtomicInteger extends Number implements java.io.Serializable {
    // 使用 volatile 关键字保证内存可见性
    private volatile int value;

    // 利用Unsafe类的CAS方法来实现原子操作
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            // 反射获取value字段的内存偏移地址
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    public final int get() {
        return value;
    }

    public final boolean compareAndSet(int expect, int update) {
        // 利用Unsafe提供的CAS方法,如果当前值==预期值,则更新为新值
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    // 其他方法省略...
}

代码演示

以下是一个简单的AtomicInteger使用示例:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInt = new AtomicInteger(0);

        // 示例:原子更新
        int oldValue = atomicInt.get();
        int newValue = oldValue + 1;
        atomicInt.compareAndSet(oldValue, newValue);

        System.out.println(atomicInt.get()); // 输出 1
    }
}

总结

原子类通过底层指令来提供非阻塞的算法,以实现线程安全。它们比传统的锁性能更好,因为线程之间不会因为锁竞争而出现阻塞。原子类是实现高效并发程序的重要工具。在实际编程中,应当优先考虑使用原子类来保证数据操作的原子性,从而减少同步的开销。