Java并发之JUC原子类(5)

1

今天我们来聊聊java.util.concurrent.atomic包下的原子类,所谓原子类就是具有原子/原子操作特征的类,在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰。

Java8下原子类包括:

原子更新基本类型
  • AtomicInteger 整型原子类
  • AtomicLong 长整型原子类
  • AtomicBoolean 布尔型原子类
原子更新数组
  • AtomicIntegerArray 整型数组原子类
  • AtomicLongArray 长整型数组原子类
  • AtomicReferenceArray 引用类型数组原子类
原子更新引用
  • AtomicReference 引用类型原子类
  • AtomicReferenceFieldUpdater 原子更新引用类型里的字段
  • AtomicMarkableReference 原子更新带有标记位的引用类型
原子更新字段
  • AtomicIntegerFieldUpdater 原子更新整型字段的更新器
  • AtomicLongFieldUpdater 原子更新长整型字段的更新器
  • AtomicStampedReference 原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。

所谓的CASABA问题:

Java并发之JUC原子类(5)_第1张图片
ABA问题.png

2

我们选取上述四个类型的各一个原子类进行源码解读,了解大概原理即可。

在原子类里,都是使用Unsafe类进行CAS操作,大家有时间可以看看Unsafe类,虽然在Java9之后的版本被删除了,但是真的值得一看。

2.1 AtomicInteger

说简单点,AtomicInteger就是利用底层类无限循环进行CAS操作,直到成功为止。

    /**
     *
     * @since 1.5
     * @author Doug Lea
     */
    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        // 使用Unsafe.compareAndSwapInt进行CAS更新操作
        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); }
        }
    
        // 使用volatile修饰value 可以保证可见性和防止指令重排
        private volatile int value;
    
        /**
         * 有参构造,设置value = initialValue
         */
        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
    
        /**
         * 空构造,value = 0
         */
        public AtomicInteger() {}
    
        /**
         * 获取当前的value
         */
        public final int get() {
            return value;
        }
    
        /**
         * 设置value值
         */
        public final void set(int newValue) {
            value = newValue;
        }
    
        /**
         * 惰性设置value值
         * unsafe.putOrderedInt() 不保证值的改变立即被其他线程看到
         * 而lazySet()的用法就是在不需要让共享变量的修改立刻让其他线程可见的时候,以设置普通变量的方式来修改共享状态,可以减少不必要的内存屏障,从而提高程序执行的效率。
         */
        public final void lazySet(int newValue) {
            unsafe.putOrderedInt(this, valueOffset, newValue);
        }
    
        /**
         * 原子性的设置新值并返回旧值
         */
        public final int getAndSet(int newValue) {
            return unsafe.getAndSetInt(this, valueOffset, newValue);
        }
    
        /**
         * 如果当前值等于expect(预期值),则原子性地将该值设置为给定的update(更新值)。
         */
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    
        /**
         * 如果当前值等于expect(预期值),则原子性地将该值设置为给定的update(更新值)。
         * 和上面的方法只是语义不同
         * weakCompareAndSet无法保证处理操作目标的volatile变量外的其他变量的执行顺序( 编译器和处理器为了优化程序性能而对指令序列进行重新排序 ),同时也无法保证这些变量的可见性。
         */
        public final boolean weakCompareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    
        /**
         * 原子性地将当前值加1,并返回旧值
         */
        public final int getAndIncrement() {
            return unsafe.getAndAddInt(this, valueOffset, 1);
        }
    
        /**
         * 原子性地将当前值减1,并返回旧值
         */
        public final int getAndDecrement() {
            return unsafe.getAndAddInt(this, valueOffset, -1);
        }
    
        /**
         * 原子性地将当前值加delta,并返回旧值
         */
        public final int getAndAdd(int delta) {
            return unsafe.getAndAddInt(this, valueOffset, delta);
        }
    
        /**
         * 原子性地将当前值加1,并返回新值
         */
        public final int incrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
        }
    
        /**
         * 原子性地将当前值减1,并返回新值
         */
        public final int decrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
        }
    
        /**
         * 原子性地将当前值加delta,并返回新值
         */
        public final int addAndGet(int delta) {
            return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回旧值。
         */
        public final int getAndUpdate(IntUnaryOperator updateFunction) {
            int prev, next;
            do {
                prev = get();
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSet(prev, next));
            return prev;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回新值。
         */
        public final int updateAndGet(IntUnaryOperator updateFunction) {
            int prev, next;
            do {
                prev = get();
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSet(prev, next));
            return next;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回旧值。
         *
         * IntBinaryOperator函数式接口:
         *
         * AtomicInteger.getAndAccumulate(3, (i, j) -> {
         *   // 通过给定的函数,返回要设置的结果
         *   return i * 10 * j
         * });
         * i是value
         * j是3
         */
        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;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回新值。
         *
         * IntBinaryOperator函数式接口:
         *
         * AtomicInteger.getAndAccumulate(3, (i, j) -> {
         *   // 通过给定的函数,返回要设置的结果
         *   return i * 10 * j
         * });
         * i是value
         * j是3
         */
        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;
        }
    
        /**
         * Returns the String representation of the current value.
         * @return the String representation of the current value
         */
        public String toString() {
            return Integer.toString(get());
        }
    
        /**
         * 继承自抽象类Number后,实现的抽象方法
         */
        public int intValue() {
            return get();
        }
    
        /**
         * 继承自抽象类Number后,实现的抽象方法
         */
        public long longValue() {
            return (long)get();
        }
    
        /**
         * 继承自抽象类Number后,实现的抽象方法
         */
        public float floatValue() {
            return (float)get();
        }
    
        /**
         * 继承自抽象类Number后,实现的抽象方法
         */
        public double doubleValue() {
            return (double)get();
        }
    
    }

2.2 AtomicIntegerArray

原子性的更新数组里的某个元素。

里面有几段代码写的很有意思,值得玩味。

    /**
     * 整型数组元素原子性更新器
     * @since 1.5
     * @author Doug Lea
     */
    public class AtomicIntegerArray implements java.io.Serializable {
        private static final long serialVersionUID = 2862133569453604235L;
    
        // 使用Unsafe类进行CAS操作
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        // unsafe.arrayBaseOffset() 获取数组第一个元素的偏移地址
        private static final int base = unsafe.arrayBaseOffset(int[].class);
        // 该类型的字节位移数
        private static final int shift;
        // 数组值
        private final int[] array;
    
        // 静态块
        static {
            // 获取数组中元素的增量地址
            int scale = unsafe.arrayIndexScale(int[].class);
            // 按位与操作后 比较是否等于0,如果不等于0,则抛出异常
            if ((scale & (scale - 1)) != 0)
                throw new Error("data type scale not a power of two");
            // 就不在这里解释这段代码的含义了,触及到了底层,有机会写一篇文章
            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;
        }
    
        /**
         * 有参构造函数,参数为数组长度
         * 并对array进行初始化操作
         */
        public AtomicIntegerArray(int length) {
            array = new int[length];
        }
    
        /**
         * 有参构造函数,参数为数组
         * 并对参数array进行克隆,然后赋值给array
         */
        public AtomicIntegerArray(int[] array) {
            // Visibility guaranteed by final field guarantees
            this.array = array.clone();
        }
    
        /**
         * 返回数组长度
         */
        public final int length() {
            return array.length;
        }
    
        /**
         * 获取数组指定下标的元素
         */
        public final int get(int i) {
            return getRaw(checkedByteOffset(i));
        }
    
        /**
         * 私有方法
         * 通过偏移量获取数组元素
         */
        private int getRaw(long offset) {
            return unsafe.getIntVolatile(array, offset);
        }
    
        /**
         * 设置数组指定下标元素值
         */
        public final void set(int i, int newValue) {
            unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
        }
    
        /**
         * 延迟设置数组指定下标元素值
         */
        public final void lazySet(int i, int newValue) {
            unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
        }
    
        /**
         * 原子性的设置数组指定元素值并返回旧值
         */
        public final int getAndSet(int i, int newValue) {
            return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);
        }
    
        /**
         * 进行CAS操作设置数组指定下标元素值
         */
        public final boolean compareAndSet(int i, int expect, int update) {
            return compareAndSetRaw(checkedByteOffset(i), expect, update);
        }
    
        private boolean compareAndSetRaw(long offset, int expect, int update) {
            return unsafe.compareAndSwapInt(array, offset, expect, update);
        }
    
        /**
         * 进行CAS操作设置数组指定元素值
         * 和上面的方法只是语义不同
         * weakCompareAndSet无法保证处理操作目标的volatile变量外的其他变量的执行顺序( 编译器和处理器为了优化程序性能而对指令序列进行重新排序 ),同时也无法保证这些变量的可见性。
         */
        public final boolean weakCompareAndSet(int i, int expect, int update) {
            return compareAndSet(i, expect, update);
        }
    
        /**
         * 原子性的对数组指定下标的元素值加1,并返回旧值
         */
        public final int getAndIncrement(int i) {
            return getAndAdd(i, 1);
        }
    
        /**
         * 原子性的对数组指定下标的元素值减1,并返回旧值
         */
        public final int getAndDecrement(int i) {
            return getAndAdd(i, -1);
        }
    
        /**
         * 原子性的对数组指定下标的元素值加delta,并返回旧值
         */
        public final int getAndAdd(int i, int delta) {
            return unsafe.getAndAddInt(array, checkedByteOffset(i), delta);
        }
    
        /**
         * 原子性的对数组指定下标的元素值加1,并返回新值
         */
        public final int incrementAndGet(int i) {
            return getAndAdd(i, 1) + 1;
        }
    
        /**
         * 原子性的对数组指定下标的元素值减1,并返回新值
         */
        public final int decrementAndGet(int i) {
            return getAndAdd(i, -1) - 1;
        }
    
        /**
         * 原子性的对数组指定下标的元素值加delta,并返回新值
         */
        public final int addAndGet(int i, int delta) {
            return getAndAdd(i, delta) + delta;
        }

        /**
         * 原子性地用给定函数的结果更新数组指定下标的元素值,并返回旧值。
         */
        public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
            long offset = checkedByteOffset(i);
            int prev, next;
            do {
                prev = getRaw(offset);
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSetRaw(offset, prev, next));
            return prev;
        }
    
        /**
         * 原子性地用给定函数的结果更新数组指定下标的元素值,并返回新值。
         */
        public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
            long offset = checkedByteOffset(i);
            int prev, next;
            do {
                prev = getRaw(offset);
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSetRaw(offset, prev, next));
            return next;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回旧值。
         * 
         * IntBinaryOperator函数式接口:
         * 
         * atomicIntegerArray.getAndAccumulate(0, 3, (i, j) -> {
         *     log.info("i:" + i);
         *     log.info("j:" + j);
         *     return i + j;
         * });
         * i: 数组对应下标的元素值
         * j: 3
         */
        public final int getAndAccumulate(int i, int x, IntBinaryOperator accumulatorFunction) {
            long offset = checkedByteOffset(i);
            int prev, next;
            do {
                prev = getRaw(offset);
                next = accumulatorFunction.applyAsInt(prev, x);
            } while (!compareAndSetRaw(offset, prev, next));
            return prev;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回新值。
         *
         * IntBinaryOperator函数式接口:
         *
         * atomicIntegerArray.getAndAccumulate(0, 3, (i, j) -> {
         *     log.info("i:" + i);
         *     log.info("j:" + j);
         *     return i + j;
         * });
         * i: 数组对应下标的元素值
         * j: 3
         */
        public final int accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction) {
            long offset = checkedByteOffset(i);
            int prev, next;
            do {
                prev = getRaw(offset);
                next = accumulatorFunction.applyAsInt(prev, x);
            } while (!compareAndSetRaw(offset, prev, next));
            return next;
        }
    
        /**
         * Returns the String representation of the current values of array.
         * @return the String representation of the current values of array
         */
        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(' ');
            }
        }
    
    }

2.3 AtomicReference

原子更新引用类型

    /**
     * 原子更新引用类型
     * @since 1.5
     * @author Doug Lea
     * @param  The type of object referred to by this reference
     */
    public class AtomicReference implements java.io.Serializable {
        private static final long serialVersionUID = -1848883965231344442L;
    
        // 使用Unsafe类进行CAS操作
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        // 值偏移地址
        private static final long valueOffset;
    
        // 静态块
        static {
            try {
                // 计算值的偏移地址
                valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    
        // 值,也就是我们要操作的值
        private volatile V value;
    
        /**
         * 有参构造
         */
        public AtomicReference(V initialValue) {
            value = initialValue;
        }
    
        /**
         * 无参构造
         */
        public AtomicReference() {}
    
        /**
         * 获取当前值
         */
        public final V get() {
            return value;
        }
    
        /**
         * 设置值
         */
        public final void set(V newValue) {
            value = newValue;
        }
    
        /**
         * 惰性设置value值
         */
        public final void lazySet(V newValue) {
            unsafe.putOrderedObject(this, valueOffset, newValue);
        }
    
        /**
         * 如果当前值等于expect(预期值),则原子性地将该值设置为给定的update(更新值)。
         */
        public final boolean compareAndSet(V expect, V update) {
            return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
        }
    
        /**
         * 如果当前值等于expect(预期值),则原子性地将该值设置为给定的update(更新值)。
         * 和上面的方法只是语义不同
         * weakCompareAndSet无法保证处理操作目标的volatile变量外的其他变量的执行顺序( 编译器和处理器为了优化程序性能而对指令序列进行重新排序 ),同时也无法保证这些变量的可见性。
         */
        public final boolean weakCompareAndSet(V expect, V update) {
            return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
        }
    
        /**
         * 原子性的设置值并返回旧值
         */
        @SuppressWarnings("unchecked")
        public final V getAndSet(V newValue) {
            return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回旧值。
         */
        public final V getAndUpdate(UnaryOperator updateFunction) {
            V prev, next;
            do {
                prev = get();
                next = updateFunction.apply(prev);
            } while (!compareAndSet(prev, next));
            return prev;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回新值。
         */
        public final V updateAndGet(UnaryOperator updateFunction) {
            V prev, next;
            do {
                prev = get();
                next = updateFunction.apply(prev);
            } while (!compareAndSet(prev, next));
            return next;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回旧值。
         *
         * BinaryOperator函数式接口:
         *
         * atomicReference.getAndAccumulate(2, (i, j) -> {
         *     log.info("i:" + i);
         *     log.info("j:" + j);
         *     return i + j;
         * });
         * i: value
         * j: 2
         */
        public final V getAndAccumulate(V x, BinaryOperator accumulatorFunction) {
            V prev, next;
            do {
                prev = get();
                next = accumulatorFunction.apply(prev, x);
            } while (!compareAndSet(prev, next));
            return prev;
        }
    
        /**
         * 原子性地用给定函数的结果更新当前值,并返回新值。
         *
         * BinaryOperator函数式接口:
         * atomicReference.getAndAccumulate(2, (i, j) -> {
         *     log.info("i:" + i);
         *     log.info("j:" + j);
         *     return i + j;
         * });
         * i: value
         * j: 2
         */
        public final V accumulateAndGet(V x, BinaryOperator accumulatorFunction) {
            V prev, next;
            do {
                prev = get();
                next = accumulatorFunction.apply(prev, x);
            } while (!compareAndSet(prev, next));
            return next;
        }
    
        /**
         * Returns the String representation of the current value.
         * @return the String representation of the current value
         */
        public String toString() {
            return String.valueOf(get());
        }
    
    }

2.4 AtomicIntegerFieldUpdater

AtomicIntegerArray要想原子地更新字段类需要如下过程

  • 因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法 newUpdater() 创建一个更新器,并且需要设置想要更新的类和属性。
  • 更新类的字段(属性)必须使用 publicvolatile 修饰符,且变量类型只能用int,不能使用Integer

AtomicIntegerArray就不贴源码了,有点多,但是源码不难,看一看即可。贴一个使用的例子吧

    @Slf4j
    public class JunitTest {
    
        @Setter
        @Getter
        @AllArgsConstructor
        public class OrderTest {
            public volatile int age;
        }
    
        @Test
        public void test0() {
            OrderTest orderTest = new OrderTest(18);
    
            AtomicIntegerFieldUpdater orderTestUpdater = AtomicIntegerFieldUpdater.newUpdater(OrderTest.class, "age");
    
            orderTestUpdater.incrementAndGet(orderTest);
    
            orderTestUpdater.get(orderTest);
    
            log.info("age: "+ orderTest.age);
    
        }
    }

输出结果为:

    age: 19

你可能感兴趣的:(Java并发之JUC原子类(5))