• JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类


    JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类

    Unsafe

    Java中无法直接操作一块内存区域,不能像C++中那样可以自己申请内存和释放内存。Java中的Unsafe类为我们提供了类似C++手动管理内存的能力。Unsafe类是"final"的,不允许继承。

    Number类(abstract)

    xxxValue()方法:将 Number 对象转换为xxx数据类型的值并返回。

    Atomic Boolean-Integer-Long UML图

    AtomicInteger源码

    获得value字段相对于AtomicInteger对象“起始地址”的偏移量:

    • Unsafe.getUnsafe();获取unsafe对象;

    • public native long objectFieldOffset(Field var1);方法用于获取某个字段相对Java对象的“起始地址”的偏移量

      • 一个java对象可以看成是一段内存,各个字段都得按照一定的顺序放在这段内存里,同时考虑到对齐要求,可能这些字段不是连续放置的,用这个方法能准确地告诉你某个字段相对于对象的起始内存地址的字节偏移量,因为是相对偏移量,所以它其实跟某个具体对象又没什么太大关系,跟class的定义和虚拟机的内存模型的实现细节更相关。
    • AtomicInteger.class.getDeclaredField("value")是拿到atomicInteger的value字段的field对象

    • valueoffset是拿到value的相对于AtomicInteger对象的地址偏移量valueOffset

    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); }
    }
    
    private volatile int value;
    

    构造函数/get/set

     public AtomicInteger(int initialValue) {
         value = initialValue;
     }
    
    public AtomicInteger() {
    }
    
    public final int get() {
            return value;
    }
    
    public final void set(int newValue) {
    	value = newValue;
    }
    

    基于native方法的原子操作

    getAnd×××方法,get在前就是先获取值,然后操作,类似于i++;get在后则类似于i--,先操作,然后返回操作后的值。

    AtomicInteger 的 getAndIncrement、getAndDecrement、getAndAdd、incrementAndGet、decrementAndGet、addAndGet 都是使用unsafe.getAndAddInt方法直接操作底层内存偏移地址对应的整型数值进行加减操作;getAndAccumulate、accumulateAndGet、updateAndGet方法都是通过输入IntUnaryOperator接口类型的参数来实现逻辑的。

    AtomicInteger中方法写法比较类似,以updateAndGet为例说明,其他方法在下面有注释

    • get()获取当前值pre,将给定函数应用于当前值,原子更新结果next,返回更新后的值next
    • CAS操作:while判断当前共享变量是否与自己获取的prev值相等
      • 相等:设置当前共享变量值为next,跳出while循环,返回next值(getAndUpdate返回prev)
      • 不相等:说明有其他线程修改共享变量,while循环继续运行
    • 即允许共享变量被多线程读写,while循环再次尝试自旋机制(无锁并发)
    public final int updateAndGet(IntUnaryOperator updateFunction) {
    	int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }
    

    set方法跟lazySet的区别

        public final void set(int newValue) {
            value = newValue;
        }
        public final void lazySet(int newValue) {
            unsafe.putOrderedInt(this, valueOffset, newValue);
        }
    

    set方法跟lazySet的区别:

    ​ set方法的设置操作在写操作的前后都加了内存屏障,因为AtomicInteger中的value是volatile修饰的。而lazySet方法并不是直接的操作value字段,而是通过Unsafe类的putOrderedInt方法先通过初始化时候计算出的vlaue字段的偏移变量找到字段地址,然后调用本地方法进行操作的,在本地方法中只在写操作前面加了一个屏障,而后面没有加。

    其他方法:

        //cas替换,如果旧值与预期值相同,则swap
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
        //与compareAndSet方法一样,为什么要用这个方法
        public final boolean weakCompareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    	//原子操作返回当前值,设置新值
        public final int getAndSet(int newValue) {
            return unsafe.getAndSetInt(this, valueOffset, newValue);
        }
    	//value++,返回的是原来的值
        public final int getAndIncrement() {
            return unsafe.getAndAddInt(this, valueOffset, 1);
        }
    	//value--,返回的是原来的值
        public final int getAndDecrement() {
            return unsafe.getAndAddInt(this, valueOffset, -1);
        }
    	//返回value,然后value+=delta
        public final int getAndAdd(int delta) {
            return unsafe.getAndAddInt(this, valueOffset, delta);
        }
    	//++value,返回的是+1操作之后的value
        public final int incrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
        }
    	//--value
        public final int decrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
        }
    	//value+=delta,然后返回value
        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 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;
        }
    

    AtomicLong源码与AtomicInteger源码结构上几乎相同,不再说明

    AtomicBoolean

    与AtomicInteger相同的部分

    对比AtomicInteger,AtomicBoolean内部同样包含一个value(int)属性

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicBoolean.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    
    private volatile int value;
    

    构造函数

    有参构造函数就是把传进来的boolean转化成了int

    public AtomicBoolean(boolean initialValue) {
        value = initialValue ? 1 : 0;
    }
    public AtomicBoolean() {
    }
    

    其他原子操作方法

    AtomicBoolean的其他方法本质上和AtomicInteger没有什么区别,只是操作之前都要把传进来的boolean类型的参数转化为int。

    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    
    public boolean weakCompareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    
    public final void set(boolean newValue) {
        value = newValue ? 1 : 0;
    }
    
    public final void lazySet(boolean newValue) {
        int v = newValue ? 1 : 0;
        unsafe.putOrderedInt(this, valueOffset, v);
    }
    public final boolean getAndSet(boolean newValue) {
        boolean prev;
        do {
            prev = get();
        } while (!compareAndSet(prev, newValue));
        return prev;
    }
    

    未经作者同意请勿转载

    本文来自博客园作者:aixueforever,原文链接:https://www.cnblogs.com/aslanvon/p/15244236.html

  • 相关阅读:
    麻省理工公开课:线性代数 第4课 A的LU分解
    麻省理工公开课:线性代数 第3课 乘法和逆矩阵
    麻省理工公开课:线性代数 第2课 矩阵消元
    麻省理工公开课:线性代数 第1课 方程组的几何解释
    线性代数导论(一)向量介绍
    鸟哥的linux私房菜——第6章 Linux的文件权限与目录配置
    Python学习(七)数组读写和保存
    Python学习(六)向量化
    Python学习(五)Numpy通用函数汇总
    Python学习(四)数组和矩阵
  • 原文地址:https://www.cnblogs.com/aslanvon/p/15244236.html
Copyright © 2020-2023  润新知