zoukankan      html  css  js  c++  java
  • AtomicXXX系列类使用分析


    本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。

    并发编程系列博客传送门


    java.util.concurrent.atomic中,普通的原子类型有以下四种:

    • AtomicBoolean:提供对基本数据类型boolean的原子性更新操作。
    • AtomicInteger:提供对基本数据类型int的原子性更新操作。
    • AtomicLong:提供对基本数据类型long的原子性更新操作。
    • AtomicReference:这是一个泛型类,提供对引用类型的原子性更新操作。

    数组相关的操作类有:

    • AtomicLongArray:提供对int[]数组元素的原子性更新操作。
    • AtomicIntegerArray:提供对long[]数组元素的原子性更新操作。
    • AtomicReferenceArray:提供对引用类型[]数组元素的原子性更新操作。

    由于上面的原子操作类的实现原理差不多,我们这边就选择AtomicInteger来分析。

    代码分析

    构造函数

    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        //Unsafe类提供底层的CAS机制 
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        //valueOffset是value值的内存地址值偏移值,这个值的作用是获取value在主内存中的值
        private static final long valueOffset;
        //类加载的时候获取valueOffset的值
        static {
            try {
                valueOffset = unsafe.objectFieldOffset
                    (AtomicInteger.class.getDeclaredField("value"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    
        //AtomicInteger具体的值存放在这个变量中,
        //这个变量使用volatile修饰,具有可见性
        private volatile int value;
        
        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
    
        //默认为0
        public AtomicInteger() {
        }
    }
    

    get和set方法分析

    //value使用volatile修饰,每次能拿到最新值
    public final int get() {
        return value;
    }
    
    //value使用volatile修饰,赋值操作具有原子性,所以这个操作也是线程安全的
    //这个方法和compareAndSet方法的区别是:compareAndSet方法会判断预期值和当前值,而set方法不会做任何判断,直接更新
    // set方法不会在意原始值是多少,而compareAndSet会确保主内存中的值和预期值相等才更新。
    public final void set(int newValue) {
        value = newValue;
    }
    
    //这个方法可能比较令人疑惑,我查了下unsafe的putOrderedInt方法,如下
    
    /**  Sets the value of the integer field at the specified offset in the
      * supplied object to the given value. This is an ordered or lazy
      * version of <code>putIntVolatile(Object,long,int)</code>, which
      * doesn't guarantee the immediate visibility of the change to other
      * threads. It is only really useful where the integer field is
      * <code>volatile</code>, and is thus expected to change unexpectedly.
      */
    上面的意思大致是:putOrderedInt方法不保证可见性,只有在变量是volatile修饰时才有用,
    我们这边的value变量就是用volatile修饰的,所以我认为AtomicInteger的`set`方法和`lazySet`方法
    功能是一致的。
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }
    
    //将value设置成给定值,并返回旧值
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    //使用CAS机制更新
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //使用CAS机制更新
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //CAS加1,并且返回原始值
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    //CAS减1,并且返回原始值
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
    //CAS加减delta值,并且返回原始值
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    //CAS加1,并且返回最新值
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    //CAS减1,并且返回最新值
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
    //CAS加减delta值,并且返回最新值
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }
    

    策略更新

    下面几个方法个人觉得不是很有用,和上面的区别就是更新的值不是穿进去的,而是通过IntUnaryOperatorIntBinaryOperator接口算出来的。

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

    简单总结

    总体来说,AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference原理比较简单:使用CAS保证原子性,使用volatile保证可见性,最终能保证共享变量操作的线程安全。

    AtomicLongArray、AtomicIntArray和AtomicReferenceArray的实现原理略有不同,是用CAS机制配合final机制来实现共享变量操作的线程安全的。感兴趣的同学可以自己分析下,也是比较简单的。

  • 相关阅读:
    python笔记之条件语句、循环语句、迭代器和生成器
    浅谈IO和NIO
    浅谈java自定义类加载器
    浅谈Synchronized和ReentrantLock
    软工1816 · 第三次作业
    软工1816 · 第二次作业
    软工1816 · 第一次作业
    简单的自我介绍
    The Last
    第七次课程作业
  • 原文地址:https://www.cnblogs.com/54chensongxia/p/12161719.html
Copyright © 2011-2022 走看看