Java 原子操作

Java 原子类包括以下几种类型:

  1. AtomicBoolean:原子布尔类型,提供原子性的读取和设置操作。
  2. AtomicInteger:原子整数类型,提供原子性的读取、设置、增加、减少、比较和交换操作。
  3. AtomicLong:原子长整型,提供原子性的读取、设置、增加、减少、比较和交换操作。
  4. AtomicIntegerArray:原子整数数组,提供原子性的数组元素读取、设置、增加、减少、比较和交换操作。
  5. AtomicLongArray:原子长整型数组,提供原子性的数组元素读取、设置、增加、减少、比较和交换操作。
  6. AtomicReference:原子引用类型,提供原子性的引用读取和设置操作。
  7. AtomicStampedReference:带时间戳的原子引用类型,可以避免 ABA 问题。
  8. AtomicMarkableReference:带标记位的原子引用类型,可以用于标记某个对象是否被删除等。

AtomicInteger 原理

AtomicInteger 是 Java 并发包中提供的一个原子类,用于实现原子性操作的整型变量。它的原理是利用了 CPU 提供的原子性操作指令,通过 CAS(Compare and Swap)算法实现原子性操作。

CAS 算法是一种无锁算法,通过比较当前内存地址的值与期望值是否相等,如果相等则将新的值写入该内存地址,否则不做任何操作。CAS 算法的基本操作包括三个参数:内存地址 V、期望值 A 和新值 B。如果 V 的值等于 A,则将 V 的值修改为 B,否则不做任何操作。CAS 算法的实现通常由硬件层面提供支持,可以保证原子性操作的高效性和正确性。

在 AtomicInteger 类中,原子性操作的实现就是利用了 CAS 算法。例如,对于 AtomicInteger 的 incrementAndGet() 方法,其实现大致如下:

1. 获取当前 AtomicInteger 的值 value。

2. 将 value 和 1 相加,得到新的值 newValue。

3. 利用 CAS 算法,将内存地址 V 的值与期望值 A(即原来的 value)比较,如果相等,则将 V 的值修改为新值 B(即 newValue),并返回修改后的值。

4. 如果 CAS 操作失败,则重新执行步骤 1 到 3,直到 CAS 操作成功为止。

通过这种方式,AtomicInteger 类可以实现原子性的自增、自减、比较和交换等操作,避免了多线程环境下的数据竞争问题。同时,由于 CAS 算法是一种无锁算法,因此可以避免了锁的开销和竞争带来的性能损失,具有较好的性能和可伸缩性。

AutomicInteger 源码详解

AtomicInteger 是 Java 中用于实现原子性操作的类之一,其源码主要包含以下几个方面:

  1. value:AtomicInteger 的内部整型变量,使用 volatile 关键字来保证多线程环境下的可见性和有序性。
private volatile int value;
  1. AtomicInteger():AtomicInteger 的无参构造方法,用于初始化 value 的值为 0。
public AtomicInteger() {
    this(0);
}
  1. AtomicInteger(int initialValue):AtomicInteger 的有参构造方法,用于初始化 value 的值为指定的初始值。
public AtomicInteger(int initialValue) {
    value = initialValue;
}
  1. get():获取当前 AtomicInteger 的值。
public final int get() {
    return value;
}
  1. set(int newValue):设置当前 AtomicInteger 的值为指定的新值。
public final void set(int newValue) {
    value = newValue;
}
  1. compareAndSet(int expect, int update):比较并设置当前 AtomicInteger 的值。如果当前值等于期望值 expect,则将当前值修改为新值 update,返回 true;否则不做任何操作,返回 false。
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
  1. getAndSet(int newValue):设置当前 AtomicInteger 的值为指定的新值,并返回修改前的值。
public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}
  1. getAndIncrement():原子性自增操作,将当前 AtomicInteger 的值加 1,并返回自增前的值。
public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}
  1. getAndDecrement():原子性自减操作,将当前 AtomicInteger 的值减 1,并返回自减前的值。
public final int getAndDecrement() {
    return unsafe.getAndAddInt(this, valueOffset, -1);
}
  1. incrementAndGet():原子性自增操作,将当前 AtomicInteger 的值加 1,并返回自增后的值。
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
  1. decrementAndGet():原子性自减操作,将当前 AtomicInteger 的值减 1,并返回自减后的值。
public final int decrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}

以上是 AtomicInteger 类的主要方法和字段,它们都是基于 CAS(Compare and Swap)算法实现的,保证了在多线程环境下的原子性操作。

原子数组

AtomicIntegerArray 原理

AtomicIntegerArray 是 Java 并发包中提供的一个原子操作类,可以实现对整型数组的原子操作。它的原理是通过底层调用 sun.misc.Unsafe 类的方法来实现对数组元素的 CAS 操作,从而保证多线程并发访问时的数据安全。

具体来说,AtomicIntegerArray 中的核心方法包括 get、set、getAndAdd、getAndIncrement、getAndDecrement、getAndSet 和 compareAndSet 等。其中,get 和 set 方法分别用于获取和设置指定下标的数组元素的值,它们不涉及原子操作;getAndAdd、getAndIncrement、getAndDecrement 和 getAndSet 方法则是进行原子操作的方法,它们都是通过 do-while 循环不断尝试 CAS 操作,直到成功为止,然后返回旧值;compareAndSet 方法是进行原子操作的核心方法,它使用 Unsafe 类的 compareAndSwapInt() 方法来实现 CAS 操作,如果操作成功则返回 true,否则返回 false。

为了实现对数组元素的 CAS 操作,AtomicIntegerArray 中使用了 sun.misc.Unsafe 类的一些方法,包括 compareAndSwapInt、arrayBaseOffset 和 arrayIndexScale 等。其中,compareAndSwapInt 方法是用于实现 CAS 操作的方法,它的作用是比较指定位置的数组元素的值是否等于期望值,如果相等则将其设为新值,返回操作是否成功的布尔值;arrayBaseOffset 和 arrayIndexScale 方法则是用于计算数组元素的地址偏移量的方法,它们分别返回数组在内存中的基地址和元素之间的偏移量,从而可以计算出数组元素在内存中的地址偏移量,方便进行 CAS 操作。

总之,AtomicIntegerArray 的原理是通过底层调用 Unsafe 类的方法实现对整型数组的原子操作,从而保证多线程并发访问时的数据安全。

AtomicIntegerArray 源码解析

public class AtomicIntegerArray implements java.io.Serializable {
    private static final long serialVersionUID = 2862133569453604235L;

    // 数组元素,使用 volatile 修饰以保证内存可见性
    private final int[] array;

    // 构造方法,将传入的数组复制一份作为 AtomicIntegerArray 的数组元素
    public AtomicIntegerArray(int length) {
        array = new int[length];
    }

    // 构造方法,将传入的数组复制一份作为 AtomicIntegerArray 的数组元素
    public AtomicIntegerArray(int[] array) {
        this.array = array.clone();
    }

    // 获取指定下标的数组元素的值
    public final int get(int i) {
        return array[i];
    }

    // 设置指定下标的数组元素的值
    public final void set(int i, int newValue) {
        array[i] = newValue;
    }

    // 获取指定下标的数组元素的值,并将其加上指定的 delta 值
    public final int getAndAdd(int i, int delta) {
        // do-while 循环,直到 CAS 成功为止
        int oldValue;
        do {
            oldValue = get(i); // 获取当前值
        } while (!compareAndSet(i, oldValue, oldValue + delta)); // 比较并交换,如果失败则继续循环
        return oldValue; // 返回旧值
    }

    // 获取指定下标的数组元素的值,并将其加上 1
    public final int getAndIncrement(int i) {
        return getAndAdd(i, 1);
    }

    // 获取指定下标的数组元素的值,并将其减去 1
    public final int getAndDecrement(int i) {
        return getAndAdd(i, -1);
    }

    // 获取指定下标的数组元素的值,并将其设为指定的 newValue 值
    public final int getAndSet(int i, int newValue) {
        // do-while 循环,直到 CAS 成功为止
        int oldValue;
        do {
            oldValue = get(i); // 获取当前值
        } while (!compareAndSet(i, oldValue, newValue)); // 比较并交换,如果失败则继续循环
        return oldValue; // 返回旧值
    }

    // 比较指定下标的数组元素的值是否等于 expect,如果相等则将其设为 update
    public final boolean compareAndSet(int i, int expect, int update) {
        // 使用 unsafe.compareAndSwapInt() 方法实现 CAS 操作
        return unsafe.compareAndSwapInt(array, byteOffset(i), expect, update);
    }

    // 获取数组元素在数组中的偏移量(即下标乘以元素大小)
    private static int byteOffset(int i) {
        return i << 2; // 相当于 i * 4
    }

    // 获取 Unsafe 实例,用于实现 CAS 操作
    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
    private static final long base = unsafe.arrayBaseOffset(int[].class);
    private static final long shift;

    static {
        int scale = unsafe.arrayIndexScale(int[].class);
        if ((scale & (scale - 1)) != 0) {
            throw new Error("data type scale not a power of two");
        }
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }

    // 计算数组元素在内存中的地址偏移量
    private static long calcLongOffset(int i) {
        return ((long) i << shift) + base;
    }
}

原子更新器

AtomicLongFieldUpdater原理

AtomicLongFieldUpdater 是 Java 并发包中提供的一种工具类,用于实现对某个对象的 long 类型字段的原子操作。它可以让我们利用原子性操作实现对共享变量的高效访问,避免使用锁机制带来的性能损耗和死锁问题。

AtomicLongFieldUpdater 的实现原理是利用反射机制和 CAS(Compare-And-Swap)操作实现对共享变量的原子操作。具体来说,AtomicLongFieldUpdater 类通过反射机制访问对象的 long 类型字段,然后调用 Unsafe 类的 compareAndSwapLong 方法实现对字段的原子操作。

CAS 操作是一种原子性操作,它可以保证多线程并发访问时的数据安全。CAS 操作的基本思想是,先获取共享变量的当前值,然后比较这个值是否等于期望值,如果相等,则将共享变量的值设为新值,否则不做任何操作。如果多个线程同时尝试对同一个共享变量进行 CAS 操作,只有一个线程能够成功,其他线程将会失败,需要重新尝试。

AtomicLongFieldUpdater 利用 CAS 操作实现了对共享变量的原子操作。例如,可以通过 AtomicLongFieldUpdater 对某个类的 long 类型字段进行原子操作,而不需要使用锁机制。

需要注意的是,使用 AtomicLongFieldUpdater 操作字段时,要求该字段必须是 volatile 类型的,否则可能会出现数据不一致的问题。

总之,AtomicLongFieldUpdater 是 Java 并发包中提供的一种工具类,它利用反射机制和 CAS 操作实现对某个对象的 long 类型字段的原子操作,可以提高多线程并发访问的性能和安全性。

AtomicLongFieldUpdater源码分析

public abstract class AtomicLongFieldUpdater {
    // 获取一个对象的 long 类型字段的值
    public abstract long get(T obj);

    // 设置一个对象的 long 类型字段的值
    public abstract void set(T obj, long newValue);

    // 比较并设置一个对象的 long 类型字段的值,如果当前值等于期望值,则设置为新值
    public abstract boolean compareAndSet(T obj, long expect, long update);

    // 弱化版的 compareAndSet,不保证成功设置字段值,但执行效率更高
    public abstract boolean weakCompareAndSet(T obj, long expect, long update);

    // 对一个对象的 long 类型字段进行增加操作,并返回新的值
    public abstract long getAndAdd(T obj, long delta);

    // 对一个对象的 long 类型字段进行增加操作,并返回新的值
    public abstract long addAndGet(T obj, long delta);

    // 创建一个 AtomicLongFieldUpdater 实例,用于更新指定类的指定字段
    public static  AtomicLongFieldUpdater newUpdater(Class tclass, String fieldName) {
        // 参数校验
        if (tclass == null || fieldName == null) {
            throw new NullPointerException();
        }

        // 获取字段的反射对象
        final Field field;
        try {
            field = tclass.getDeclaredField(fieldName);
            if (!Modifier.isVolatile(field.getModifiers())) {
                throw new IllegalArgumentException("Must be volatile");
            }
            Class<?> fieldType = field.getType();
            if (fieldType != long.class) {
                throw new IllegalArgumentException("Must be long type");
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

        // 创建 AtomicLongFieldUpdaterImpl 实例
        return new AtomicLongFieldUpdaterImpl(field);
    }
}
class AtomicLongFieldUpdaterImpl extends AtomicLongFieldUpdater {
    // 字段的偏移量
    private final long offset;

    // 构造方法,通过反射获取字段的偏移量
    AtomicLongFieldUpdaterImpl(Field field) {
        // 参数校验
        if (!Modifier.isVolatile(field.getModifiers())) {
            throw new IllegalArgumentException("Must be volatile");
        }
        Class<?> fieldType = field.getType();
        if (fieldType != long.class) {
            throw new IllegalArgumentException("Must be long type");
        }

        // 获取字段的偏移量
        this.offset = unsafe.objectFieldOffset(field);
    }

    // 获取一个对象的 long 类型字段的值
    public long get(T obj) {
        return unsafe.getLongVolatile(obj, offset);
    }

    // 设置一个对象的 long 类型字段的值
    public void set(T obj, long newValue) {
        unsafe.putLongVolatile(obj, offset, newValue);
    }

    // 比较并设置一个对象的 long 类型字段的值,如果当前值等于期望值,则设置为新值
    public boolean compareAndSet(T obj, long expect, long update) {
        return unsafe.compareAndSwapLong(obj, offset, expect, update);
    }

    // 弱化版的 compareAndSet,不保证成功设置字段值,但执行效率更高
    public boolean weakCompareAndSet(T obj, long expect, long update) {
        return unsafe.compareAndSwapLong(obj, offset, expect, update);
    }

    // 对一个对象的 long 类型字段进行增加操作,并返回新的值
    public long getAndAdd(T obj, long delta) {
        long current, next;
        do {
            current = get(obj);
            next = current + delta;
        } while (!compareAndSet(obj, current, next));
        return current;
    }

    // 对一个对象的 long 类型字段进行增加操作,并返回新的值
    public long addAndGet(T obj, long delta) {
        long current, next;
        do {
            current = get(obj);
            next = current + delta;
        } while (!compareAndSet(obj, current, next));
        return next;
    }
}

AtomicLongFieldUpdater 是一个抽象类,用于实现对某个对象的 long 类型字段的原子操作。该类的主要方法包括 get、set、compareAndSet、weakCompareAndSet、addAndGet 和 getAndAdd 等,通过反射机制和 Unsafe 类实现对共享变量的原子操作。

小结:

小心这些原子类中的set和get方法。没有使用cas就不保证原子性了,只能保证可见性和有序性。

页面更新:2024-04-29

标签:原子   操作   期望值   数组   字段   算法   元素   对象   类型   方法

1 2 3 4 5

上滑加载更多 ↓
Top