什么是原子操作?
原子操作(Atomic Operations)是在多线程环境中执行时不会被线程调度机制打断的操作;这类操作一旦开始,就会一直运行到结束,中间不会出现上下文切换,从而保证了操作的完整性。在并发编程中,原子操作往往是必须的,以保证数据的一致性和完整性。
在计算机科学中,原子性意味着一个操作或者一系列操作是不可分割的,即要么全部完成要么全部不做,不会停留在中间某个步骤。这在多线程环境中尤其重要,原子性操作可以防止其他线程看到不一致的数据状态。
Java中的原子类
Java中的原子操作主要由java.util.concurrent.atomic包提供的类来实现。这些类利用了底层的CAS(Compare-And-Swap)操作来保证操作的原子性。CAS操作是处理器提供的一种原子性指令,用于在并发算法中实现无锁的线程安全编程。
以下是一些常用的Java原子类:
AtomicBoolean:一个布尔值,可以原子地更新。AtomicInteger:一个整数值,可以原子地更新。AtomicLong:一个长整型数值,可以原子地更新。AtomicReference:一个对象引用,可以原子地更新。- 数组类型:如
AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray,它们分别提供了原子更新数组中的元素。 - 字段更新器:如
AtomicIntegerFieldUpdater,AtomicLongFieldUpdater和AtomicReferenceFieldUpdater,它们提供了原子更新对象的字段。 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
}
}
总结
原子类通过底层指令来提供非阻塞的算法,以实现线程安全。它们比传统的锁性能更好,因为线程之间不会因为锁竞争而出现阻塞。原子类是实现高效并发程序的重要工具。在实际编程中,应当优先考虑使用原子类来保证数据操作的原子性,从而减少同步的开销。