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;
}
原子地减少当前值并返回新值。