包介绍
JDK的atomic包提供了一组原子类,用于多线程环境中的原子操作,确保线程安全和高性能。
Atomic包是Java在并发编程中的重要工具,它利用CAS(Compare-And-Swap)机制保证操作的原子性,同时避免了重量级锁的使用,提高了并发性能。Atomic包中的类通过底层处理器提供的原子指令实现,但不同的CPU架构可能提供的原子指令不同,有时可能需要某种形式的内部锁,因此不能绝对保证线程不被阻塞。

基本类型
AtomicInteger
提供了一种线程安全的方式来操作整数。

主要提供了以下方法:

getAndIncrement(): 获取当前值并自增,返回旧值。get(): 获取当前值。compareAndSet(int expect, int update): 如果当前值等于预期值(expect),则将其更新为新的值(update)。如果更新成功,返回 true;否则返回 false。getAndSet(int newValue): 获取当前值并设置为指定的新值,返回旧值。floatValue(): 将当前值转换为 float 类型。getAndAdd(int delta): 获取当前值并加上指定的增量(delta),返回旧值。getAndUpdate(IntUnaryOperator updateFunction): 获取当前值并应用给定的一元操作函数(updateFunction),返回旧值。intValue(): 将当前值转换为 int 类型。getAndAccumulate(int x, IntBinaryOperator accumulatorFunction): 获取当前值并与给定的值(x)应用二元操作函数(accumulatorFunction),返回旧值。toString(): 返回当前值的字符串表示形式。lazySet(int newValue): 设置当前值为指定的新值,但不保证立即可见性,可能会延迟到下一次访问。incrementAndGet(): 自增并返回新值。accumulateAndGet(int x, IntBinaryOperator accumulatorFunction): 与给定的值(x)应用二元操作函数(accumulatorFunction)并返回结果。decrementAndGet(): 自减并返回新值。longValue(): 将当前值转换为 long 类型。addAndGet(int delta): 增加指定的增量(delta)并返回新值。doubleValue(): 将当前值转换为 double 类型。weakCompareAndSet(int expect, int update): 类似于 compareAndSet,但如果当前值不等于预期值,它可能不会立即失败,而是尝试再次进行比较和设置。这在某些情况下可以提高性能,但可能导致不一致的结果。updateAndGet(IntUnaryOperator updateFunction): 应用给定的一元操作函数(updateFunction)并返回结果。set(int newValue): 设置当前值为指定的新值。
原理
-
原子性操作:AtomicInteger使用CAS(比较替换)算法来实现其内部的值的原子性更新。CAS算法是硬件级别的原子操作,它可以在没有锁的情况下进行线程安全的更新。
-
Unsafe类:AtomicInteger的内部实现使用了Unsafe类的native方法,如
compareAndSwapInt,这是一个底层的、高效的原子操作方法,它直接与操作系统和硬件交互,实现了原子性的保证。
/**
通过调用Unsafe.getUnsafe()方法获取Unsafe实例。Unsafe类提供了一些底层操作,可以直接访问对象和内存,绕过了Java的安全检查机制。
定义了一个静态常量valueOffset,用于存储字段"value"在内存中的偏移量。
在静态初始化块中,使用unsafe.objectFieldOffset方法获取字段"value"的偏移量。这个方法需要一个Field对象作为参数,因此需要先通过反射获取AtomicInteger类的"value"字段。
如果获取偏移量的过程中发生异常(例如找不到字段),则抛出一个Error。
**/
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
- 字段更新:AtomicInteger使用volatile关键字声明其内部值字段,确保字段的可见性和有序性,防止指令重排序导致的问题。
private volatile int value;
- 方法实现:AtomicInteger提供了一系列的方法,如
getAndIncrement、compareAndSet等,这些方法都是利用CAS算法来实现的,它们可以在没有锁的情况下,保证操作的原子性。
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
-
性能优势:由于AtomicInteger不需要使用锁,它通常比使用
synchronized关键字或者显式锁(如ReentrantLock)的性能要好,尤其是在高并发的情况下。 -
内存开销:AtomicInteger相对于普通的Integer会有稍微大一点的内存开销,因为它需要额外的内存来存储一些操作所需的元数据。
-
限制:尽管AtomicInteger提供了原子性的保证,但是它不能保证操作的“逻辑原子性”。例如,如果你需要检查值,然后基于这个值进行更新(比如计数器小于10就增加),这样的操作序列就不能保证原子性,因为这个过程涉及到多个步骤,而CAS只能保证单个操作的原子性。
-
可扩展性:AtomicInteger是可扩展的,意味着你可以用它作为更复杂原子操作的基础,通过组合和扩展AtomicInteger的功能,可以构建更复杂的原子操作。
-
线程兼容性:AtomicInteger的操作是线程兼容的,这意味着在多线程环境中,你可以安全地使用AtomicInteger而不用担心线程安全问题。
-
使用场景:AtomicInteger适用于那些需要线程安全的整数操作,但不需要使用锁或者不希望有锁带来的性能开销的场景。
AtomicBoolean
类提供了一种线程安全的方式来操作布尔值。

主要提供了以下方法:

-
getAndSet(boolean newValue): 将当前值设置为指定的新值,并返回旧值。这是一个原子操作,确保在多线程环境下的一致性。 -
set(boolean newValue): 将当前值设置为指定的新值。这也是一个原子操作。 -
get(): 获取当前的布尔值。这个方法是非原子的,但在多线程环境中使用时,由于其他原子操作的存在,可以保证读取到的值是一致的。 -
compareAndSet(boolean expect, boolean update): 如果当前值等于预期值(expect),则将其更新为新的值(update)。如果更新成功,返回 true;否则返回 false。这是一个典型的CAS(Compare-and-Swap)操作,通常用于无锁编程。 -
lazySet(boolean newValue): 将当前值设置为指定的新值,但可能会延迟该操作直到下一次访问。这是一种优化手段,可以减少不必要的内存屏障开销。 -
weakCompareAndSet(boolean expect, boolean update): 类似于compareAndSet,但如果当前值不等于预期值,它可能不会立即失败,而是尝试再次进行比较和设置。这在某些情况下可以提高性能,但可能导致不一致的结果。 -
toString(): 返回当前布尔值的字符串表示形式。这个方法是非原子的,但在多线程环境中使用时,由于其他原子操作的存在,可以保证读取到的值是一致的。
AtomicLong
类提供了一种线程安全的方式来操作长整数。

主要提供了以下方法:

VMSupportsCS8(): 返回一个布尔值,表示虚拟机是否支持CS8(Compare and Swap)操作。longValue(): 获取当前值作为长整型(long)。intValue(): 获取当前值作为整型(int)。toString(): 返回当前值的字符串表示形式。incrementAndGet(): 自增并返回新值。getAndAccumulate(long x, LongBinaryOperator accumulatorFunction): 获取当前值并与给定的值(x)应用二元操作函数(accumulatorFunction),返回旧值。getAndSet(long newValue): 获取当前值并设置为指定的新值,返回旧值。doubleValue(): 将当前值转换为双精度浮点数(double)。set(long newValue): 设置当前值为指定的新值。weakCompareAndSet(long expect, long update): 如果当前值等于预期值(expect),则将其更新为新的值(update)。如果更新成功,返回 true;否则返回 false。getAndUpdate(LongUnaryOperator updateFunction): 获取当前值并应用给定的一元操作函数(updateFunction),返回旧值。getAndIncrement(): 获取当前值并自增,返回旧值。accumulateAndGet(long x, LongBinaryOperator accumulatorFunction): 与给定的值(x)应用二元操作函数(accumulatorFunction)并返回结果。getAndAdd(long delta): 获取当前值并加上指定的增量(delta),返回旧值。get(): 获取当前值。lazySet(long newValue): 设置当前值为指定的新值,但不保证立即可见性,可能会延迟到下一次访问。compareAndSet(long expect, long update): 如果当前值等于预期值(expect),则将其更新为新的值(update)。如果更新成功,返回 true;否则返回 false。updateAndGet(LongUnaryOperator updateFunction): 应用给定的一元操作函数(updateFunction)并返回结果。floatValue(): 将当前值转换为单精度浮点数(float)。addAndGet(long delta): 增加指定的增量(delta)并返回新值。getAndDecrement(): 获取当前值并自减,返回旧值。decrementAndGet(): 自减并返回新值。
数组操作
AtomicIntegerArray
与AtomicLongArray类似,但是它用于操作int类型的数组。它也提供了一系列的原子操作方法,如get、set、compareAndSet等,以确保在多线程环境下对数组元素的操作是原子性的。

提供的以下方法:

getAndIncrement(int): 获取指定索引位置的当前值,并将其自增1。返回自增前的值。accumulateAndGet(int, int, IntBinaryOperator): 对指定索引位置的元素进行累加操作,并返回累加后的结果。累加操作由提供的IntBinaryOperator参数定义。getAndDecrement(int): 获取指定索引位置的当前值,并将其自减1。返回自减前的值。getAndAccumulate(int, int, IntBinaryOperator): 对指定索引位置的元素进行累加操作,并返回累加后的结果。累加操作由提供的IntBinaryOperator参数定义。compareAndSet(int, int, int): 如果指定索引位置的当前值等于预期值(第二个参数),则将其更新为新值(第三个参数)。返回一个布尔值表示是否成功更新。compareAndSetRaw(long, int, int): 类似于compareAndSet,但使用长整型索引。addAndGet(int, int): 将指定的增量(第二个参数)添加到指定索引位置的元素上,并返回结果。checkedByteOffset(int): 检查给定的偏移量是否有效,并返回相应的字节偏移量。getAndSet(int, int): 获取指定索引位置的当前值,并将其设置为新值(第二个参数)。返回旧值。byteOffset(int): 返回指定索引位置的字节偏移量。length(): 返回数组的长度。get(int): 获取指定索引位置的值。lazySet(int, int): 设置指定索引位置的值,但不保证立即可见性。decrementAndGet(int): 获取指定索引位置的当前值,并将其自减1。返回自减前的值。weakCompareAndSet(int, int, int): 如果指定索引位置的当前值等于预期值(第二个参数),则尝试将其更新为新值(第三个参数)。返回一个布尔值表示是否成功更新。toString(): 返回数组的字符串表示形式。set(int, int): 设置指定索引位置的值。getRaw(long): 获取指定索引位置的值,使用长整型索引。getAndUpdate(int, IntUnaryOperator): 获取指定索引位置的当前值,并应用给定的一元操作函数(第二个参数)。返回操作后的结果。incrementAndGet(int): 获取指定索引位置的当前值,并将其自增1。返回自增后的值。getAndAdd(int, int): 获取指定索引位置的当前值,并将其加上指定的增量(第二个参数)。返回结果。updateAndGet(int, IntUnaryOperator): 应用给定的一元操作函数(第二个参数)到指定索引位置的元素上,并返回操作后的结果。
AtomicLongArray
提供了一种线程安全的方式来操作long类型的数组。它提供了一系列的原子操作方法,如get、set、compareAndSet等,这些方法可以确保在多线程环境下对数组元素的操作是原子性的。

类方法说明:
set(int index, long newValue): 将指定索引位置的元素设置为新值。addAndGet(int index, long delta): 将指定的增量(delta)添加到指定索引位置的元素上,并返回结果。getAndUpdate(int index, LongUnaryOperator updateFunction): 获取指定索引位置的当前值,应用给定的一元操作函数(updateFunction),并将结果写回该位置,最后返回操作前的值。getAndDecrement(int index): 获取指定索引位置的当前值,将其自减1,并将结果写回该位置,最后返回操作前的值。checkedByteOffset(int index): 检查给定的索引是否有效,并返回相应的字节偏移量。getRaw(long offset): 获取指定偏移量处的元素值。lazySet(int index, long newValue): 设置指定索引位置的元素值为新值,但不保证立即可见性。length(): 返回数组的长度。compareAndSet(int index, long expect, long update): 如果指定索引位置的当前值等于预期值(expect),则将其更新为新值(update)。返回一个布尔值表示是否成功更新。accumulateAndGet(int index, long x, LongBinaryOperator accumulatorFunction): 对指定索引位置的元素进行累加操作,并返回累加后的结果。累加操作由提供的累加器函数(accumulatorFunction)定义。getAndIncrement(int index): 获取指定索引位置的当前值,并将其自增1,然后将结果写回该位置,最后返回操作前的值。getAndAccumulate(int index, long x, LongBinaryOperator accumulatorFunction): 对指定索引位置的元素进行累加操作,并返回累加后的结果。累加操作由提供的累加器函数(accumulatorFunction)定义。getAndAdd(int index, long delta): 获取指定索引位置的当前值,将其加上指定的增量(delta),然后将结果写回该位置,最后返回操作前的值。updateAndGet(int index, LongUnaryOperator updateFunction): 应用给定的一元操作函数(updateFunction)到指定索引位置的元素上,并返回操作后的结果。getAndSet(int index, long newValue): 获取指定索引位置的当前值,并将其设置为新值(newValue)。返回旧值。weakCompareAndSet(int index, long expect, long update): 如果指定索引位置的当前值等于预期值(expect),则尝试将其更新为新值(update)。返回一个布尔值表示是否成功更新。incrementAndGet(int index): 获取指定索引位置的当前值,将其自增1,然后将结果写回该位置,最后返回操作后的值。toString(): 返回数组的字符串表示形式。byteOffset(int index): 返回指定索引位置的字节偏移量。decrementAndGet(int index): 获取指定索引位置的当前值,将其自减1,然后将结果写回该位置,最后返回操作后的值。get(int index): 获取指定索引位置的值。compareAndSetRaw(long offset, long expect, long update): 如果指定偏移量处的当前值等于预期值(expect),则将其更新为新值(update)。返回一个布尔值表示是否成功更新。



















