并发-JUC之ATOMIC包分析

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.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 中用于实现累加器的类,它们提供了一种线程安全的方式来对一个数值类型的变量进行累加操作。

  1. LongAdder 类是 Java 中实现累加器的 long 类型的类,它提供了一种线程安全的方式来对 long 类型的变量进行累加操作。该类维护一个 long 类型的变量,并提供了一系列方法来对这个变量进行原子性操作,例如 add、increment、decrement 等。
  2. 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。

 

基本方法

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 中用于实现累加器的类,它们提供了一种线程安全的方式来对一个数值类型的变量进行累加操作。

  1. LongAdder 类是 Java 中实现累加器的 long 类型的类,它提供了一种线程安全的方式来对 long 类型的变量进行累加操作。该类维护一个 long 类型的变量,并提供了一系列方法来对这个变量进行原子性操作,例如 add、increment、decrement 等。
  2. 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。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值