zoukankan      html  css  js  c++  java
  • 【JUC】AtomicInteger源码

    首先要知道CAS

    CAS

    Compare and Swap,即比较再交换;

    区别于synchronouse同步锁的一种乐观锁(是一种无锁算法)

    CAS有3个操作数,

    • 内存地址,以直接从内存中获取旧值;
    • 旧的预期值A,代码中的旧值;
    • 要修改的新值B

    当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做;

    CAS是CPU级别的指令操作,上述操作是一步原子操作;

    缺陷

    ABA问题

    有可能value被改了,又被改回来了,那么CAS算法是无法发现value已经被修改过了,误认为没有被修改;

    AtomicInteger

    private volatile int value;
    private static final long valueOffset;
    // 通过unsafe对象,来进行native操作
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    

    两个重要属性:

    • value:就是创建此对象的值
    • valueOffset

    valueOffset

    就是说:AtomicInteger对象,在创建完成之后,在内存中分配一片内存,其中此对象的每个属性相对于这片内存的偏移量就已经确定了;

    valueOffset就是AtomicInteger对象的value属性在内存中的偏移量;

    通过下面的Unsafe类的native方法,直接从内存中获取value的值;

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

    getAndAdd方法

    我们要执行下面一系列操作时:

    AtomicInteger i = new AtomicInteger(0);
    int original =i.getAndAdd(3);
    
    
    1. 首先创建AtomicInteger对象,值会存放在value属性中;
    // 构造器
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    
    1. 其次调用getAndAdd方法
    // 调用getAndAdd方法
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    
    1. 此方法会调用Unsafe类下的多个Native方法

      getIntVolatilecompareAndSwapInt都是Unsafe类下的native方法;

      getIntVolatile:就是CAS中的根据内存地址,直接在内存级别获取当前旧值;

      compareAndSwapInt:就是CAS的比较修改的操作,修改成功,返回true,那么跳出循环;修改失败,继续尝试获取内存值,进行修改;

    // 再调用Unsafe类下的getAndAddInt方法
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        // CAS操作
        do {
            /**
             * var1:我们创建的AtomicInteger对象
             * var2:valueOffset
             * 就是找到此对象下,value属性在内存中的偏移量,在内存级别直接拿到value的值
             */
            var5 = this.getIntVolatile(var1, var2); 
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    	// 返回旧值
        return var5;
    }
    

    getAndIncrement方法

    getAndAdd类似

    同样是调用unsafe对象下的unsafe.getAndAddInt(this, valueOffset, 1)

    只不过delta直接传值为1;

  • 相关阅读:
    vue 移动端商城搭建 (一)
    关于mantisBT2.22安装插件Inline column configuration 2.0.0时提示缺少依赖jQuery UI Library 1.8
    mantis2.22.1中添加管理员密码修改框
    mantisbt2.22.1 中使用自带的phpmailer发送邮件(实测可用)
    Mac配置Jenkins(构建Allure模板报告)
    ATX插件机制-学习学习
    查看包名和Activity的小工具
    pytest跳过指定的测试或模块
    pytest常用命令参数
    关于pytest使用allure生成报告时,报一堆警告和缺少XX模块
  • 原文地址:https://www.cnblogs.com/mussessein/p/12635570.html
Copyright © 2011-2022 走看看