AtomicInteger 是 Java 并发编程中一个常用的类,它位于 java.util.concurrent.atomic 包下。这个类提供了一种可以在并发环境中安全地更新整数值的方法。
AtomicInteger 提供了一种无锁(lock-free)的线程安全操作整数的解决方案。
AtomicInteger 继承自 Number 类,这意味着 AtomicInteger 可以被当作一个数字对象来使用。
Number是一个抽象类,它提供了将数字对象转换为各种基本数据类型的方法,如byteValue(),shortValue(),intValue(),longValue(),floatValue(), 和doubleValue()。
构造方法
AtomicInteger 提供了2个构造方法:
AtomicInteger():创建一个初始值为 0 的 AtomicInteger 实例。AtomicInteger(int initialValue):创建一个具有指定初始值的 AtomicInteger 实例。
public AtomicInteger() {}
public AtomicInteger(int initialValue) {
value = initialValue;
}属性

private static final Unsafe U:Unsafe是一个特殊的类,它提供了硬件级别的操作,可以用来执行低级别的、不安全的操作。在AtomicInteger中,它被用来实现原子操作。U是Unsafe类的一个实例。private static final long VALUE:这是一个静态的常量,表示AtomicInteger类中value字段的内存偏移量。这个偏移量是由Unsafe类的objectFieldOffset方法获取的,它用于在更新value时提供对内存的直接访问。private volatile int value:这是AtomicInteger类中实际存储整数值的字段。volatile关键字确保了value的读写操作对所有线程立即可见,并且每次访问value都会直接从主内存中进行,而不是从线程的本地缓存中读取。
VALUE 是一个用于内部实现原子操作的元数据,它表示 value 字段的内存偏移量。而 value 是实际存储整数值的字段,它是 AtomicInteger 类的核心所在。
VALUE 是一个静态字段,因此它对于 AtomicInteger 类的所有实例都是相同的;而 value 是一个实例字段,每个 AtomicInteger 对象都有自己的 value 字段副本。
工作原理
AtomicInteger 的实现依赖于 sun.misc.Unsafe 类,该类提供了硬件级别的原子操作。在 AtomicInteger 的内部,有一个 volatile 类型的 int 变量 value,这个关键字保证了变量的可见性和有序性。
当对 AtomicInteger 进行操作时,Unsafe 类会使用 VALUE 偏移量来定位当前操作对象(即 this 指针所指向的 AtomicInteger 实例)的 value 字段,并执行相应的原子操作。而在java代码中我们可以直接操作 value 字段,但这不是原子操作。
关键的方法如 compareAndSet 利用了 Unsafe 类的 compareAndSwapInt 方法,它是一个原子操作,可以保证在多线程环境下对 value 的修改是安全的。
常用方法
int get()
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
public final int get() {
return value;
}AtomicInteger 类的 get 方法是一个用于获取当前整数值的简单方法。它提供了 VarHandle#getVolatile 的内存语义,这意味着每次调用 get 方法时,都会直接从主内存中读取 value 字段的最新值,而不是从线程的本地缓存中读取。这是由 value 字段的 volatile 修饰符保证的。
set(newValue)
同样由 value 字段的 volatile 修饰符保证最新值。
public final void set(int newValue) {
value = newValue;
}int getAndSet(newValue)
包含了get和set两个操作,java提供的 volatile 修饰符不再能保证两个操作的原子性,需要使用Unsafe来支持。
public final int getAndSet(int newValue) {
return U.getAndSetInt(this, VALUE, newValue);
}这是一个公共的final方法,它调用了一个名为U的辅助类(通常是sun.misc.Unsafe的实例)的getAndSetInt方法。这个方法的作用是原子地设置新值并返回旧值。this参数指的是当前对象的引用,VALUE是一个字段偏移量,newValue是要设置的新值。
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, newValue));
return v;
}这个方法接受一个对象o,一个偏移量offset,以及一个新值newValue。它使用一个do-while循环来实现原子交换。首先,它通过getIntVolatile获取当前值,然后尝试使用weakCompareAndSetInt来设置新值。如果设置成功(即当前值没有被其他线程改变),循环结束,返回旧值。
public native int getIntVolatile(Object o, long offset);这个本地方法(native method)用于以volatile读的方式获取对象o在偏移量offset处的int值。这意味着读操作是直接从主内存中进行,而不是从线程的本地缓存中读取。
@IntrinsicCandidate
public final boolean weakCompareAndSetInt(Object o, long offset,
int expected,
int x) {
return compareAndSetInt(o, offset, expected, x);
}这个方法尝试将对象o在偏移量offset处的值原子地更新为x,前提是当前值等于expected。如果更新成功,返回true;否则返回false。这个方法实际上委托给了compareAndSetInt方法。
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);这个本地方法尝试执行一个原子性的比较和交换操作。如果对象o在偏移量offset处的值等于expected,则将其更新为x,并返回true表示操作成功。如果值不等于expected,则不进行任何操作,并返回false。
总结getAndSet的执行流程:
- 首先,通过
getIntVolatile以volatile读的方式获取当前值。 - 然后,进入一个循环,尝试使用
compareAndSetInt原子地更新值为新值。 - 如果更新成功(没有其他线程改变值),则退出循环,返回获取的当前值。
- 如果更新失败(有其他线程改变了值),则循环继续,重新获取当前值并尝试更新。
boolean compareAndSet(expect, update)
public final boolean compareAndSet(int expectedValue, int newValue) {
return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}如果当前值等于预期值,则设置为给定的更新值。
int getAndIncrement()
详细执行流程:
调用
getAndIncrement方法时,它内部调用了名为U的辅助类(通常是sun.misc.Unsafe的实例)的getAndAddInt方法。传递的参数包括当前对象的引用this、字段VALUE的偏移量offset以及要增加的值delta(在这个例子中是1)。javapublic final int getAndIncrement() { return U.getAndAddInt(this, VALUE, 1); }在
getAndAddInt方法中,首先定义了一个变量v,用于存储当前值。javapublic final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; }进入一个 do-while 循环。在循环体内,首先通过
getIntVolatile方法以 volatile 读的方式获取对象o在偏移量offset处的 int 值,并将其赋值给变量v。这个操作确保了读取的是值是最新的,没有被缓存。接下来,调用
weakCompareAndSetInt方法,尝试将对象o在偏移量offset处的值原子地更新为v + delta(即当前值加delta)。weakCompareAndSetInt方法接受四个参数:对象o、偏移量offset、期望的当前值v和新值v + delta。在
weakCompareAndSetInt方法内部,实际上是调用了compareAndSetInt方法。compareAndSetInt是一个本地方法,它执行一个原子性的比较和交换操作。如果对象o在偏移量offset处的值确实等于期望值v,则将其更新为新值v + delta,并返回true表示操作成功。如果
compareAndSetInt方法返回true,说明更新操作成功,此时 do-while 循环结束,方法返回变量v的值,即更新前的旧值。如果
compareAndSetInt方法返回false,说明在尝试更新期间,对象o在偏移量offset处的值被其他线程改变了。在这种情况下,循环将继续执行,重新获取当前值并尝试再次更新。这个过程会一直重复,直到
compareAndSetInt方法成功地将值更新为止。
int getAndDecrement()
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}原子地减少当前值并返回旧值。
int incrementAndGet()
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}原子地增加当前值并返回新值。
等于getAndDecrement()+1。
int decrementAndGet()
public final int decrementAndGet() {
return U.getAndAddInt(this, VALUE, -1) - 1;
}原子地减少当前值并返回新值。
