1. 前言
AtomicInteger是Java中的一个原子整数类,它提供了一种在多线程环境下进行原子性操作的方法。所谓原子性操作是指不会被线程调度机制打断的操作;这些操作可以在可能被其他线程影响的情况下作为一个不可分割的整体执行。
在并发编程中,如果多个线程同时对同一个变量进行读取和写入操作,会存在竞态条件(Race Condition),导致数据不一致或错误。为了解决这种问题,Java提供了一系列的原子类,其中包括AtomicInteger。
AtomicInteger可以保证对整型变量的操作是原子性的,比如增加、减少操作。它使用了底层的CAS(Compare and Swap)操作来实现原子性。
2. 介绍CAS
AtomicInteger的实现依赖于底层的CAS(Compare-And-Swap)操作,确保其操作是原子性的。CAS是一种硬件级别的原子操作,通常由处理器直接支持,它可以在多线程环境中保证对变量的修改不会引起竞态条件。
CAS 操作
CAS 操作涉及三个值:
- 内存位置(V):需要读取和更新的变量。
- 预期值(A):当前线程认为变量应该持有的值。
- 新值(B):线程希望将变量的值更新为的新值。
CAS 过程如下:
- 检查内存位置 V 的当前值是否等于预期值 A。
- 如果相等,则将内存位置 V 的值更新为新值 B。
- 如果不相等,则不进行任何操作并返回当前值。
这个过程是一个原子操作,不会被其他线程中断。
AtomicInteger 实现原理
在 Java 中,AtomicInteger 类使用 CAS 操作来实现其方法。以下是它的一些关键方法及其实现原理:
incrementAndGet()
这是 AtomicInteger 类中一个常用方法,用于以原子方式将当前值加 1,并返回加 1 后的值。
java
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
解释:
- 获取当前值 :调用
get()
方法获取当前值。 - 计算下一个值:将当前值加 1,得到下一个值。
- CAS 操作 :调用
compareAndSet(current, next)
尝试将当前值更新为下一个值。- 如果当前值等于预期值(current),则更新成功,返回更新后的值。
- 如果当前值不等于预期值,则表示在这段时间内已经有其他线程修改了当前值。因此,循环重试,直到更新成功。
compareAndSet(int expect, int update)
这是一个本地方法(native),通常由 JVM 底层通过硬件指令实现。
java
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
解释:
- unsafe :使用了
Unsafe
类,这是一个提供底层操作的类。Unsafe
类允许进行低级别的、不受限制的内存操作。 - compareAndSwapInt:这是一个本地方法,使用底层的硬件指令来执行 CAS 操作。
为什么 AtomicInteger 是原子的
由上述实现原理可以看出,AtomicInteger 的操作是原子的,原因主要有以下几点:
- CAS 操作:底层的 CAS 操作保证了整个比较和交换步骤的原子性。
- 硬件支持:现代处理器通常提供对 CAS 操作的原生支持,这样可以确保这些操作在硬件级别上是原子的。
- 循环重试:如果 CAS 操作失败(因为其他线程修改了值),AtomicInteger 会自动进行循环重试,直到操作成功。
因此,AtomicInteger 能够在多线程环境中安全地进行整数操作,避免传统锁机制带来的性能损耗,同时确保操作的正确性。