java.util.concurrent.atomic
包提供了一些原子操作类,这些类可以在多线程环境下保证操作的原子性,从而避免了线程安全问题,里面分类如下:
- 基本类型Atomicxxx
包括AtomicInteger、AtomicLong、AtomicBoolean - 引用类型AtomicxxxReference
包括AtomicReference、AtomicStampedReference、AtomicMarkableReference - 数组类型更新AtomicxxxArray
包括:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray - 字段更新类型AtomicxxxFieldUpdater
包括:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater - 累加器类型XXXAccumulator
包括:LongAccumulator、DoubleAccumulator - 累加器类型(无锁)xxxAdder
包括LongAdder、DoubleAdder
基本类型Atomicxxx
包括AtomicInteger、AtomicLong、AtomicBoolean三个基本类型的原子操作
其中AtomicBoolean底层也是用int来实现的
java
复制代码
private volatile int value; /** * Creates a new {@code AtomicBoolean} with the given initial value. * * @param initialValue the initial value */ public AtomicBoolean(boolean initialValue) { value = initialValue ? 1 : 0; }
AtomicLong类型,和AtomicInteger很相似,区别在于,因为JVM底层对于int和long类型所占用的字节数是不一样的(int 4字节,long 8字节)
我们以AtomicInteger分析下 UML类图如下
基本方法
java
复制代码
/** * Gets the current value. * * @return the current value */ public final int get() { return value; } /** * Sets to the given value. * * @param newValue the new value */ public final void set(int newValue) { value = newValue; } /** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); }
其他方法
getAndUpdate(IntUnaryOperator updateFunction)
以原子方式获取当前对象的值,并将其传递给updateFunction
进行处理,然后将处理后的结果更新到当前对象中。最后返回处理之前的值。
java
复制代码
public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; }
使用举例
java
复制代码
AtomicInteger atomicInt = new AtomicInteger(10); int result = atomicInt.getAndUpdate(x -> x + 5); System.out.println(result); // 输出 10 System.out.println(atomicInt.get()); // 输出 15
updateAndGet(IntUnaryOperator updateFunction)
该方法接受一个 IntUnaryOperator
类型的参数 updateFunction
,该参数表示一个一元操作符,接受当前对象的值作为输入,返回一个更新后的值。
java
复制代码
public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; }
getAndAccumulate(int x,IntBinaryOperator accumulatorFunction)
用于以原子方式获取当前对象的值,并将其与给定的值 x
进行一元操作,然后将操作后的结果更新到当前对象中,并返回操作前的值。
java
复制代码
public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; }
使用举例
java
复制代码
AtomicInteger atomicInt = new AtomicInteger(10); int result = atomicInt.getAndAccumulate(5, (prev, x) -> prev * x); System.out.println(result); // 输出 10 System.out.println(atomicInt.get()); // 输出 50
accumulateAndGet(int x,IntBinaryOperator accumulatorFunction)
用于以原子方式获取当前对象的值,并将其与给定的值 x
进行一元操作,然后将操作后的结果更新到当前对象中,并返回操作后的值。
java
复制代码
public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next; }
引用类型AtomicxxxReference
AtomicReference
AtomicReference
类是 Java 中实现原子性引用类型的类,它提供了一种线程安全的方式来更新对象的引用。该类提供了一系列方法来更新和获取对象的引用,例如 get
方法用于获取当前对象的引用,set
方法用于设置对象的引用,compareAndSet
方法用于比较当前对象的引用并在匹配时更新为新的引用 与AtomicInteger方法基本相同,不同的是成员变量value改为泛型V
java
复制代码
static { try { valueOffset = unsafe.objectFieldOffset (AtomicReference.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //泛型 private volatile V value; /** * Creates a new AtomicReference with the given initial value. * * @param initialValue the initial value */ public AtomicReference(V initialValue) { value = initialValue; } ...
AtomicStampedReference
AtomicStampedReference
类是 AtomicReference
类的扩展,它提供了一种解决 ABA 问题的方法。
ABA 问题是指一个线程将对象从 A 改为 B,又从 B 改为 A,另一个线程在这个过程中将对象从 A 改为 C,然后又改回 A,此时第一个线程将不知不觉地操作了一个错误的对象。
为了解决这个问题,AtomicStampedReference
类在更新对象引用时还会更新一个时间戳,从而在比较对象引用时也需要比较时间戳。
利用内部类Pair来存储对象和对象版本
java
复制代码
private static class Pair<T> { final T reference; final int stamp; private Pair(T reference, int stamp) { this.reference = reference; this.stamp = stamp; } static <T> Pair<T> of(T reference, int stamp) { return new Pair<T>(reference, stamp); } } private volatile Pair<V> pair; /** * Creates a new {@code AtomicStampedReference} with the given * initial values. * * @param initialRef the initial reference * @param initialStamp the initial stamp */ public AtomicStampedReference(V initialRef, int initialStamp) { pair = Pair.of(initialRef, initialStamp); } ...
compareAndSet
方法的扩展版本 compareAndSet(int expectedStamp, int newStamp, V expectedReference, V newReference)
,它要求对象引用和时间戳都匹配时才进行更新。
java
复制代码
public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { Pair<V> current = pair; return expectedReference == current.reference && expectedMark == current.mark && ((newReference == current.reference && newMark == current.mark) || casPair(current, Pair.of(newReference, newMark))); }
java
复制代码
private boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); }
AtomicMarkableReference
AtomicMarkableReference
类也是 AtomicReference
类的扩展,它提供了一种解决 ABA 问题的方法,与 AtomicStampedReference
类不同的是,它使用一个 boolean 标记来指示对象是否被修改过。该类提供了 compareAndSet
方法的扩展版本
java
复制代码
private static class Pair<T> { final T reference; //int版本改为布尔型 final boolean mark; private Pair(T reference, boolean mark) { this.reference = reference; this.mark = mark; } static <T> Pair<T> of(T reference, boolean mark) { return new Pair<T>(reference, mark); } } private volatile Pair<V> pair; /** * Creates a new {@code AtomicMarkableReference} with the given * initial values. * * @param initialRef the initial reference * @param initialMark the initial mark */ public AtomicMarkableReference(V initialRef, boolean initialMark) { pair = Pair.of(initialRef, initialMark); }
compareAndSet(boolean expectedMark, boolean newMark, V expectedReference, V newReference)
,它要求对象引用和标记都匹配时才进行更新
java
复制代码
public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) { Pair<V> current = pair; return expectedReference == current.reference && expectedMark == current.mark && ((newReference == current.reference && newMark == current.mark) || casPair(current, Pair.of(newReference, newMark))); }
java
复制代码
private boolean casPair(Pair<V> cmp, Pair<V> val) { return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val); }
数组类型更新AtomicxxxArray
AtomicIntegerArray
、AtomicLongArray
和 AtomicReferenceArray
都是 Java 中用于实现线程安全的原子性操作的类,它们提供了对整型数组、长整型数组和引用类型数组的原子性操作
这三个方法都差不多,我们看下AtomicIntegerArray实现
java
复制代码
private static final long serialVersionUID = 2862133569453604235L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final int base = unsafe.arrayBaseOffset(int[].class); private static final int shift; private final int[] array; static { //返回int[]数组中一个元素占用的字节数 int scale = unsafe.arrayIndexScale(int[].class); if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); //Integer.numberOfLeadingZeros(scale)是 Java 中的一个静态方法,用于计算一个整数值的二进制表示中从左边开始连续的 0 的个数 //用 31 减去这个数,就得到了一个元素占用的字节数的位移数 shift = 31 - Integer.numberOfLeadingZeros(scale); } private long checkedByteOffset(int i) { if (i < 0 || i >= array.length) throw new IndexOutOfBoundsException("index " + i); return byteOffset(i); } private static long byteOffset(int i) { return ((long) i << shift) + base; } public AtomicIntegerArray(int length) { array = new int[length]; }
java
复制代码
/** * Atomically sets the element at position {@code i} to the given * value and returns the old value. * * @param i the index * @param newValue the new value * @return the previous value */ public final int getAndSet(int i, int newValue) { return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue); }
字段更新类型AtomicxxxFieldUpdater
AtomicIntegerFieldUpdater
、AtomicLongFieldUpdater
和 AtomicReferenceFieldUpdater
都是 Java 中用于实现对某个类的字段进行原子性操作的类,它们提供了一种线程安全的方式来更新类的字段。AtomicIntegerFieldUpdater
类是 Java 中实现对某个类的 int 类型字段进行原子性操作的类,它提供了一种线程安全的方式来更新指定类的 int 类型字段。该类使用反射机制来获取类的字段并进行原子性操作,因此需要满足一定的条件,例如字段必须是 volatile 类型并且不能是 final 类型
使用案例
java
复制代码
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class MyClass { private volatile int count; private static final AtomicIntegerFieldUpdater<MyClass> updater = AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "count"); public void increment() { updater.incrementAndGet(this); } public int getCount() { return count; } public static void main(String[] args) { MyClass obj = new MyClass(); obj.increment(); System.out.println(obj.getCount()); } }
其他AtomicLongFieldUpdater
和 AtomicReferenceFieldUpdater
也是同样的原理
累加器类型XXXAccumulator
LongAccumulator
和 DoubleAccumulator
类是 Java 中用于实现累加器的类,它们提供了一种线程安全的方式来对一个数值类型的变量进行累加操作。 LongAccumulator
类是 Java 中实现累加器的 long 类型的类,它提供了一种线程安全的方式来对 long 类型的变量进行累加操作。该类维护一个 long 类型的变量,并提供了一系列方法来对这个变量进行原子性操作,例如 accumulate
、get
、getAndAdd
等
java
复制代码
public class LongAccumulator extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L; private final LongBinaryOperator function; private final long identity; public LongAccumulator(LongBinaryOperator accumulatorFunction, long identity) { this.function = accumulatorFunction; base = this.identity = identity; }
使用举例
java
复制代码
import java.util.concurrent.atomic.LongAccumulator; public class MyClass { private static final LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE); public static void main(String[] args) { accumulator.accumulate(10); accumulator.accumulate(20); accumulator.accumulate(30); System.out.println("Max value: " + accumulator.get());//30 } }
在上面的例子中,定义了一个名为 MyClass
的类,其中包含一个名为 accumulator
的静态常量,它是 LongAccumulator
类的一个实例,用于计算一组数字的最大值。
在类的 main
方法中,调用 accumulator.accumulate
方法三次,将数字 10、20 和 30 依次累加到累加器中。然后,使用 accumulator.get()
方法获取累加器中的最大值,并输出到控制台。
需要注意的是,LongAccumulator
类的构造函数需要传入两个参数,第一个参数是一个函数对象,用于指定对两个 long 类型的值进行计算的方式,例如 Long::max
表示计算两个值的最大值。第二个参数是累加器的初始值。在上面的例子中,accumulator
的初始值为 Long.MIN_VALUE
,表示累加器的初始值为 long 类型的最小值。
DoubleAccumulator
类与 LongAccumulator
类类似,它是 Java 中实现累加器的 double 类型的类,提供了类似的一系列方法来对 double 类型的变量进行原子性操作。
累加器类型(无锁)xxxAdder
LongAdder
和 DoubleAdder
类是 Java 中用于实现累加器的类,它们提供了一种线程安全的方式来对一个数值类型的变量进行累加操作。
LongAdder
类是 Java 中实现累加器的 long 类型的类,它提供了一种线程安全的方式来对 long 类型的变量进行累加操作。该类维护一个 long 类型的变量,并提供了一系列方法来对这个变量进行原子性操作,例如add
、increment
、decrement
等。DoubleAdder
类与LongAdder
类类似,它是 Java 中实现累加器的 double 类型的类,提供了类似的一系列方法来对 double 类型的变量进行原子性操作。 使用范例
java
复制代码
import java.util.concurrent.atomic.LongAdder; public class MyClass { private static final LongAdder adder = new LongAdder(); public static void main(String[] args) { adder.add(10); adder.add(20); adder.add(30); System.out.println("Total value: " + adder.sum()); } }
在上面的例子中,定义了一个名为 MyClass
的类,其中包含一个名为 adder
的静态常量,它是 LongAdder
类的一个实例,用于计算一组数字的总和。
在类的 main
方法中,调用 adder.add
方法三次,将数字 10、20 和 30 依次累加到累加器中。然后,使用 adder.sum()
方法获取累加器中的总和,并输出到控制台。
需要注意的是,在使用 LongAdder
类和 DoubleAdder
类时,可以使用多个线程同时调用 add
方法,从而实现高效的并发累加。与 LongAccumulator
和 DoubleAccumulator
不同的是,LongAdder
和 DoubleAdder
不需要指定一个初始值,因为它们的初始值为 0。