并发编程四-原子操作(比较并替换CAS操作)

目录

一,Unsafe类介绍

1,获取Unsafe对象

2,Unsafe提供的方法

2.1 对类的静态属性的读与写

2.2 对对象成员属性的读和写

2.3 比较并替换操作

2.4 测试这些方法:

二,CAS操作:

1,CAS是什么?

2,使用CAS实现一个线程安全的自增功能:

3,CAS的一些问题

3.1 ABA问题

3.2 如果多次操作失败对CPU开销大

3.3 一次原子操作只能更新一个共享变量的值

三、JDK提供的原子操作类

1,对基本类型的原子操作

1.1 int型的原子操作

1.2 long类型的原子操作

1.3 boolean型的原子操作

2,对数组类型的原子操作

2.1 任意类型的数组:

2.3 long类型数组的原子操作

3,对引用类型的原子操作

3.1 AtomicReferenceFieldUpdater

3.2 AtomicReference


一,Unsafe类介绍

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力.

1,获取Unsafe对象

在Unsafe源码中提供了一个静态方法来获取Unsafe对象,源码如下:

@CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

但是我们不能直接使用,因为这个方法检测了类加载器,我们自己写的代码的类加载器是sun.misc.Launcher$AppClassLoader,不是代码中判断的那个,所以调用这个方法会抛出异常。

但是我们可以使用反射来获取这个对象的实例:

代码如下:

            // 通过反射获取Unsafe实例对象
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe)f.get(null);

2,Unsafe提供的方法

该类提供了类似c/c++语言一样,直接对系统内存进行操作的方法。

例如:

对类和对象的属性的获取与修改;

直接分配内存空间,内存赋值,释放内存等操作;

提供了CAS操作;

线程调度:线程的挂起与唤醒、加锁和释放锁。

类的加载和内存屏障相关等操作方法。

 

下面来简单使用一下这个类的方法:

先提供一个测试类用于测试用:

类中提供了一个静态属性(platformVersion)和一个成员属性(fileCount)

class MyEneity{
    private static String platformVersion = "1.0-pm4v1";
    private int fileCount = 336;

    public int getFileCount() {
        return fileCount;
    }

    @Override
    public String toString() {
        return "MyEneity {" +
                "platformVersion = " + platformVersion +
                ", fileCount = " + fileCount +
                '}';
    }
}

2.1 对类的静态属性的读与写

// 获取类属性的地址偏移量
long platformVersionOffset = unsafe.staticFieldOffset(MyEneity.class.getDeclaredField("platformVersion"));

// 获取类的属性的值
String platformVersion = unsafe.getObject(MyEneity.class, platformVersionOffset).toString();

// 修改类属性的值
unsafe.putObject(MyEneity.class, platformVersionOffset,"new-version-val");

2.2 对对象成员属性的读和写

// 获取对象属性的地址偏移量
long fileCountOffset = unsafe.objectFieldOffset(myEneity.getClass().getDeclaredField("fileCount"));

// 获取对象属性的值
int fileCount = unsafe.getInt(myEneity, fileCountOffset);

// 修改对象属性的值
unsafe.putInt(myEneity,fileCountOffset,0);

2.3 比较并替换操作

// 如果替换成功则返回true
unsafe.compareAndSwapInt(对象, 属性地址偏移量, 旧的值, 新的值);

简单写一个myEntity对象中fileCount的值线程安全的自增方法,如下:

private static void atomicIncrement(MyEneity myEneity,long valueOffset){
        int oldValue ;
        do {
            oldValue = myEneity.getFileCount();
        } while(!unsafe.compareAndSwapInt(myEneity, valueOffset, oldValue, oldValue + 1));
    }

2.4 测试这些方法:

2.4.1 完整代码:

package com.salulu.t10;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class UnsafeTest {

    private static final Unsafe unsafe;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe)f.get(null);
        } catch (Exception ex) { throw new Error(ex); }
    }

    public static void main(String[] args) throws InterruptedException, NoSuchFieldException {
        MyEneity myEneity = new MyEneity();
        // 获取对象属性的地址偏移量
        long fileCountOffset = unsafe.objectFieldOffset(myEneity.getClass().getDeclaredField("fileCount"));
        // 获取类属性的地址偏移量
        long platformVersionOffset = unsafe.staticFieldOffset(MyEneity.class.getDeclaredField("platformVersion"));
        System.out.println("fileCount的地址偏移量:"+fileCountOffset);
        System.out.println("platformVersion的地址偏移量:"+platformVersionOffset);

        // 获取对象属性的值
        int fileCount = unsafe.getInt(myEneity, fileCountOffset);
        // 获取类的属性的值
        String platformVersion = unsafe.getObject(MyEneity.class, platformVersionOffset).toString();
        System.out.println("fileCount="+fileCount);
        System.out.println("platformVersion="+platformVersion);

        System.out.println("修改前:"+myEneity.toString());
        // 修改类属性的值
        unsafe.putObject(MyEneity.class, platformVersionOffset,"new-version-val");
        // 修改对象属性的值
        unsafe.putInt(myEneity,fileCountOffset,0);
        System.out.println("修改后:"+myEneity.toString());

        // 两个线程,每个线程各自增10000次,结果应该为20000
        Thread threadA = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                atomicIncrement(myEneity,fileCountOffset);
            }
        });
        Thread threadB = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                atomicIncrement(myEneity,fileCountOffset);
            }
        });
        // 启动两个线程
        threadA.start();
        threadB.start();
        // 主线程等待两个线程执行结束
        threadA.join();
        threadB.join();
        // 输出执行结果
        // 如果fileCount的值为20000,说明使用cas操作实现了自增操作的线程安全
        System.out.println("执行完自增方法后:"+myEneity.toString());

    }


    private static void atomicIncrement(MyEneity myEneity,long valueOffset){
        int oldValue ;
        do {
            oldValue = myEneity.getFileCount();
        } while(!unsafe.compareAndSwapInt(myEneity, valueOffset, oldValue, oldValue + 1));
    }

}

class MyEneity{
    private static String platformVersion = "1.0-pm4v1";
    private int fileCount = 336;

    public int getFileCount() {
        return fileCount;
    }

    @Override
    public String toString() {
        return "MyEneity {" +
                "platformVersion = " + platformVersion +
                ", fileCount = " + fileCount +
                '}';
    }
}

2.4.2,运行结果:

fileCount的地址偏移量:12
platformVersion的地址偏移量:104
fileCount=336
platformVersion=1.0-pm4v1
修改前:MyEneity {platformVersion = 1.0-pm4v1, fileCount = 336}
修改后:MyEneity {platformVersion = new-version-val, fileCount = 0}
执行完自增方法后:MyEneity {platformVersion = new-version-val, fileCount = 20000}

 

二,CAS操作:

1,CAS是什么?

CAS全称是Compare and Swap,即比较并交换的意思,其原理是通过cpu的原子指令来实现原子操作。

将获取存储在内存地址的原值和指定的内存地址进行比较,只有当他们相等时,交换指定的预期值和内存中的值,若不相等,则重新获取存储在内存地址的原值,这整个过程是原子操作。

2,使用CAS实现一个线程安全的自增功能:

代码中有详细的注释:

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class MyAtomicOP {

    //Unsafe类提供了硬件级别的原子操作
    private static final Unsafe unsafe;
    //目标Java变量中的目标属性的偏移地址。
    private static final long valueOffset;
    // 被操作的目标对象
    private volatile int value;

    public MyAtomicOP(int value){
        this.value = value;
    }

    static {
        try {
            // 通过反射获取Unsafe实例对象
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe)f.get(null);
            // 获取value属性的内存偏移地址
            valueOffset = unsafe.objectFieldOffset(MyAtomicOP.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    public int getValue() {
        return value;
    }

    // 对valueOffset这个地址的值(也就是value的值)进行+1操作
    void atomicIncrement(){
        int oldValue ;
        do {
            // 获取this对象地址在valueOffset这个地址偏移量指向的值
            oldValue = unsafe.getIntVolatile(this, valueOffset);
            // 进行比较并替换操作,直到成功为止
            // 参数说明:
            // 第一个参数:包含要修改属性的对象 当前是MyAtomicOPTest对象实例,这里用this
            // 第二个参数:this对象中整型需要操作的属性的地址偏移量 当前是MyAtomicOPTest对象的valueOffset属性
            // 第三个参数:需要修改的属性的值 当前是MyAtomicOPTest对象的value属性
            // 第四个参数:需要修改为多少,目标值
        } while(!unsafe.compareAndSwapInt(this, valueOffset, oldValue, oldValue + 1));
    }
}

测试一下:

public class MyAtomicMainTest {

    public static void main(String[] args) throws InterruptedException {
        MyAtomicOP unsafeTest = new MyAtomicOP(0);
        // 创建两个线程调用atomicIncrement()方法对value对象进行操作
        // 各调用10000次
        // 两个线程执行完成后value的预期结果应该是20000
        Thread threadA = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                unsafeTest.atomicIncrement();
            }
        });
        Thread threadB = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                unsafeTest.atomicIncrement();
            }
        });
        // 启动两个线程
        threadA.start();
        threadB.start();
        // 主线程等待两个线程执行结束
        threadA.join();
        threadB.join();
        // 输出执行结果
        System.out.println(unsafeTest.getValue());
    }
}

输出:

20000

3,CAS的一些问题

3.1 ABA问题

CAS操作是在更新值的时候检查下原值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,后来变成了B,然后又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。

这个问题看业务场景,如果是对于一个基本数据类型,CAS操作的中发生了ABA操作,但是业务没有影响,那么这个问题就不算问题;但是如果是需要感知数据的每一次改变,那么就需要解决ABA问题。

解决方式:给变量加上版本号,那么每次变量更新的时候把版本号加一,那么A->B->A 就会变成A1->B2->A3.

jdk提供了AtomicStampedReference类来解决ABA问题

3.2 如果多次操作失败对CPU开销大

在线程激烈争抢更新数据时,如果多次使用CAS来更新数据都失败,则会给CPU带来额外的性能开销。

3.3 一次原子操作只能更新一个共享变量的值

可以把多个数据放到同一个对象里,然后原子更新该对象:JDK提供了AtomicReference类来保证引用对象之间的原子性。

三、JDK提供的原子操作类

1,对基本类型的原子操作

1.1 int型的原子操作

AtomicInteger类

API介绍:

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                    (java.util.concurrent.atomic.AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile int value;

    /**
     * 使用给定的初始值创建一个新的AtomicInteger。
     * @param initialValue
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    public AtomicInteger() {
    }

    /**
     * 获取当前值。
     */
    public final int get() {
        return value;
    }

    /**
     * 设置为给定值。
     * @param newValue 新的值
     */
    public final void set(int newValue) {
        value = newValue;
    }

    /**
     * 设置为给定值。
     * @param newValue 新的值
     */
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }

    /**
     * 自动设置为给定值并返回旧值。
     * @param newValue 新的值
     * @return 修改前的值
     */
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }

    /**
     * 如果当前expect的值是预期值,自动将值设置为给定的更新值
     * @param expect 期望值
     * @param update 新值
     * @return {@code true} 更新成功返回true
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 如果当前expect的值是预期值,自动将值设置为给定的更新值
     * 可能会失败,并且不提供排序保证
     * @param expect 期望值
     * @param update 新值
     * @return {@code true} 更新成功返回true
     */
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 将当前值自增1
     * @return 返回旧的值
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

    /**
     * 将当前值原子递减1
     * @return 返回旧的值
     */
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

    /**
     * 原子的将给定值加上到当前值。
     * @param delta 要增加的值
     * @return 返回旧的值
     */
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }

    /**
     * 将当前值原子自增1
     * @return 返回更新后的值
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    /**
     * 将当前值原子自减1
     * @return 返回更新后的值
     */
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }

    /**
     * 原子地将给定值添加到当前值。
     *
     * @param delta 要增加的值
     * @return 返回更新后的值
     */
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

    /**
     * 使用应用给定函数的结果自动更新当前值,并返回以前的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * @param updateFunction 函数
     * @return 返回旧值
     */
    public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * 使用应用给定函数的结果自动更新当前值,并返回以前的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * @param updateFunction 函数
     * @return 返回新的值
     */
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * 使用将给定函数应用于当前值和给定值的结果自动更新当前值,并返回以前的值。
     * 函数的第一个参数是当前值,第二个参数是给定的update。
     * @param x 更新后的值
     * @param accumulatorFunction 有两个参数的函数
     * @return 旧的值
     */
    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;
    }

    /**
     * 使用将给定函数应用于当前值和给定值的结果自动更新当前值,并返回以前的值。
     * 函数的第一个参数是当前值,第二个参数是给定的要更新的值
     * @param x 当前值
     * @param accumulatorFunction 有两个参数的函数表达式
     * @return 更新的值
     */
    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;
    }


    public String toString() {
        return Integer.toString(get());
    }

    public int intValue() {
        return get();
    }

    public long longValue() {
        return (long)get();
    }

    public float floatValue() {
        return (float)get();
    }

    public double doubleValue() {
        return (double)get();
    }

}

1.2 long类型的原子操作

JDK提供AtomicLong类来操作

API与int型类似

1.3 boolean型的原子操作

JDK提供AtomicBoolean类来操作

API与int型类似

 

2,对数组类型的原子操作

2.1 任意类型的数组:

AtomicReferenceArray类

API:

/**
 * 一个对象引用数组,其中的元素可以原子更新。
 */
public class AtomicReferenceArray<E> implements java.io.Serializable {
    private static final long serialVersionUID = -6209656149925076980L;

    private static final Unsafe unsafe;
    private static final int base;
    private static final int shift;
    private static final long arrayFieldOffset;
    private final Object[] array; // must have exact type Object[]

    static {
        try {
            unsafe = Unsafe.getUnsafe();
            arrayFieldOffset = unsafe.objectFieldOffset
                    (java.util.concurrent.atomic.AtomicReferenceArray.class.getDeclaredField("array"));
            base = unsafe.arrayBaseOffset(Object[].class);
            int scale = unsafe.arrayIndexScale(Object[].class);
            if ((scale & (scale - 1)) != 0)
                throw new Error("data type scale not a power of two");
            shift = 31 - Integer.numberOfLeadingZeros(scale);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    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;
    }

    /**
     * 创建一个新的给定长度的AtomicReferenceArray,初始时所有元素为空。
     * @param length 数组长度
     */
    public AtomicReferenceArray(int length) {
        array = new Object[length];
    }

    /**
     * 创建一个新的AtomicReferenceArray,它与给定数组的长度相同,并复制其中的所有元素。
     * @param array 要从中复制元素的数组
     */
    public AtomicReferenceArray(E[] array) {
        // Visibility guaranteed by final field guarantees
        this.array = Arrays.copyOf(array, array.length, Object[].class);
    }

    /**
     * 返回数组的长度。
     */
    public final int length() {
        return array.length;
    }

    /**
     * 获取位置指定索引i处的当前值。
     * @param i 索引
     * @return 返回指定索引i处的当前值。
     */
    public final E get(int i) {
        return getRaw(checkedByteOffset(i));
    }

    @SuppressWarnings("unchecked")
    private E getRaw(long offset) {
        return (E) unsafe.getObjectVolatile(array, offset);
    }

    /**
     * 将位于位置i的元素设置为给定值。
     * @param i 角标
     * @param newValue 新的值
     */
    public final void set(int i, E newValue) {
        unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
    }

    /**
     * 将位于位置i的元素设置为给定值(非实时)
     * @param i 角标
     * @param newValue 新的值
     * @since 1.6
     */
    public final void lazySet(int i, E newValue) {
        unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
    }

    /**
     * 原子地将位于位置i的元素设置为给定值并返回旧值。
     * @param i 角标
     * @param newValue 新的值
     * @return 原来的值(旧值)
     */
    @SuppressWarnings("unchecked")
    public final E getAndSet(int i, E newValue) {
        return (E)unsafe.getAndSetObject(array, checkedByteOffset(i), newValue);
    }

    /**
     * 如果当前值是预期值,则原子地将位于位置i的元素设置为给定的更新值。
     * @param i 角标
     * @param expect 预期值
     * @param update 新值
     * @return {@code true} true为成功,false表示实际值与预期值不相等。
     */
    public final boolean compareAndSet(int i, E expect, E update) {
        return compareAndSetRaw(checkedByteOffset(i), expect, update);
    }

    private boolean compareAndSetRaw(long offset, E expect, E update) {
        return unsafe.compareAndSwapObject(array, offset, expect, update);
    }

    /**
     * 如果当前值是预期值,则原子地将位于位置i的元素设置为给定的更新值。
     * 可能会失败,并且不提供排序保证
     * @param i 角标
     * @param expect 预期值
     * @param update 新值
     * @return {@code true}
     */
    public final boolean weakCompareAndSet(int i, E expect, E update) {
        return compareAndSet(i, expect, update);
    }

    /**
     * 原子地用应用给定函数的结果更新索引i处的元素,返回之前的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * @param i 角标
     * @param updateFunction 函数表达式
     * @return 旧的值
     */
    public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
        long offset = checkedByteOffset(i);
        E prev, next;
        do {
            prev = getRaw(offset);
            next = updateFunction.apply(prev);
        } while (!compareAndSetRaw(offset, prev, next));
        return prev;
    }

    /**
     * 原子地用应用给定函数的结果更新索引i处的元素,返回之前的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * @param i 角标
     * @param updateFunction 函数表达式
     * @return 新的值
     */
    public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
        long offset = checkedByteOffset(i);
        E prev, next;
        do {
            prev = getRaw(offset);
            next = updateFunction.apply(prev);
        } while (!compareAndSetRaw(offset, prev, next));
        return next;
    }

    /**
     * 原子地用应用给定函数的结果更新索引i处的元素,返回之前的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * 函数的第一个参数是索引i处的当前值,第二个参数是给定的新值。
     * @param i 角标
     * @param x 新的值
     * @param accumulatorFunction
     * @return 旧的值
     */
    public final E getAndAccumulate(int i, E x,
                                    BinaryOperator<E> accumulatorFunction) {
        long offset = checkedByteOffset(i);
        E prev, next;
        do {
            prev = getRaw(offset);
            next = accumulatorFunction.apply(prev, x);
        } while (!compareAndSetRaw(offset, prev, next));
        return prev;
    }

    /**
     * 原子地用应用给定函数的结果更新索引i处的元素,返回更新后的值。
     * 当由于线程之间的争用而尝试更新失败时,会重新调用该函数。
     * 函数的第一个参数是索引i处的当前值,第二个参数是给定的新值。
     * @param i 角标
     * @param x 新的值
     * @param accumulatorFunction a side-effect-free function of two arguments
     * @return 新值
     */
    public final E accumulateAndGet(int i, E x,
                                    BinaryOperator<E> accumulatorFunction) {
        long offset = checkedByteOffset(i);
        E prev, next;
        do {
            prev = getRaw(offset);
            next = accumulatorFunction.apply(prev, x);
        } while (!compareAndSetRaw(offset, prev, next));
        return next;
    }

    public String toString() {
        int iMax = array.length - 1;
        if (iMax == -1)
            return "[]";

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(getRaw(byteOffset(i)));
            if (i == iMax)
                return b.append(']').toString();
            b.append(',').append(' ');
        }
    }

    /**
     * 从流重新构造实例(即反序列化)。
     */
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException,
            java.io.InvalidObjectException {
        // Note: This must be changed if any additional fields are defined
        Object a = s.readFields().get("array", null);
        if (a == null || !a.getClass().isArray())
            throw new java.io.InvalidObjectException("Not array type");
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
        unsafe.putObjectVolatile(this, arrayFieldOffset, a);
    }

}

2.2 int数组的原子操作

AtomicIntegerArray类

API与AtomicReferenceArray类似

2.3 long类型数组的原子操作

AtomicLongArray类

API与AtomicReferenceArray类似

 

3,对引用类型的原子操作

3.1 AtomicReferenceFieldUpdater

给定对象的字段设置为给定的更新值,保存执行的原子性。

说明:一个基于反射的实用程序,允许对指定类的指定引用字段进行原子更新。这个类设计用于原子数据结构中,在这种结构中,同一个节点的几个引用字段独立地服从原子更新。

这个类中的ompareAndSet方法的保证比其他原子类的要弱。因为这个类不能确保字段的所有使用都适合于原子访问的目的,所以它只能保证在同一个Atomic对象上调用compareAndSet和set时的原子性。

API参考其他Atomic类

3.2 AtomicReference

可以原子更新对象的引用。

API参考其他Atomic类

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值