zoukankan      html  css  js  c++  java
  • 原子类AtomicInteger实现浅析

     

    1 前言

    在多线程程序中,如果多个线程同时更新一个共享变量,可能会出现预料之外的奇怪的值。普通的变量无法在多线程下做到可见性、一致性、原子性,也就无法保证线程安全。在JDK的java.util.concurrent.atomic包中提供许多原子操作类,它们可以简单、 高效、安全地更新一个变量。现在介绍其中的基本类型的原子操作类。

    基本数据类型有booleancharbyteshortintlongfloatdouble 这8种,但其原子类只有AtomicBoolean AtomicInteger AtomicLong.其他未包含的基本类型可通过一些操作转换成原子类型。如:只取AtomicInteger 的低32位(低位的两字节)可作为short 的原子类,将double放大10n倍将其变为整数,然后就可使用AtomicLong原子类。这3个类的实现基本相同,这里以AtomicInteger为例作说明

    2 方法说明

    主要API如下

    //以原子方式获取旧值并设置新值
    public final int getAndSet(int newValue)
    //以原子方式获取旧值并自增1
    public final int getAndIncrement()
    //以原子方式获取旧值并自减1
    public final int getAndDecrement()
    //以原子方式获取旧值并给当前值加delta
    public final int getAndAdd(int delta)
    //以原子方式给当前值自增1并获取新值
    public final int incrementAndGet()
    //以原子方式给当前值自减1并获取新值
    public final int decrementAndGet()
    //以原子方式给当前值加上delta并获取新值
    public final int addAndGet(int delta)

    3 实现原理

    上面的这些API都会使用到Unsafe类的相关方法,可以说原子类的实现关键在于Unsafe。AtomicInteger使用一个int类型的成员变量value来表示原子类所代表的数值, value使用volatile关键字修饰,在多线程环境中能保证其可见性。Unsafe类可以在本地内存中直接操作value.

        private volatile int value;

    AtomicInteger有两个构造方法,带参构造方法用参数指定初始值,无参数构造方法将初始值设为0

        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
        public AtomicInteger() {
        }

    Unsafe.objectFieldOffset(Field)方法能根据成员变量的反射表示形式Filed获取内存中对象起始位置objAddr至此成员变量位置fieldAddr的相对偏移量offset,在已知对象起始位置和成员变量相对偏移量offset时,可计算出成员变量在内存中的绝对地址,即fieldAddr=objAddr+offset。Unsafe是系统底层类,它的所有方法几乎都是(native)本地方法,本地方法是用C/C++实现的,C/C++方法根据变量的内存地址可直接操作变量value,它能越过访问修改符的访问限制。Unsafe操作成员变量的方法签名几乎都是XXX(Object obj,long offset ,? x),它要求调用者同时提供对象的引用obj(知道对象的引用也就能获取对象的起始地址)及成员变量的相对偏移量offset,根据这两个已知量即可求出此成员变量在内存中的绝对地址。

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

     

    原子类是基于CAS实现的,具体表现在原子类API的调用链底层使用Unsafe.compareAndSwapXX方法.

    getAndSet方法使用Unsafe.getAndSetInt实现,而getAndSetInt方法体主要是一个while自旋循环体,while循环体的核心方法是compareAndSwapInt方法,这是一个CAS方法。

    //AtomicInteger
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    //Unsafe
    public final int getAndSetInt(Object o, long offset, int newValue) {
        int v;
        do {
            v = getIntVolatile(o, offset);//先获取原来的value
            
      //如果v与此刻执行compareAndSwapInt方法时的value不等,则表明
      //value被其他线程修改了,此处compareAndSwapInt会失败,将继续自旋重试
        } while (!compareAndSwapInt(o, offset, v, newValue));
        return v;
    }
    //Unsafe 
    public final native boolean compareAndSwapInt(Object o, long offset,  int expected,  int x);//本地方法

    其他方法也基本上也是基于这种CAS机制实现,如incrementAndGet()方法。

    //AtomicInteger
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    //Unsafe
    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!compareAndSwapInt(o, offset, v, v + delta));
        return v;
    }


  • 相关阅读:
    openSUSE 13.1 Milestone 4 发布
    Neo4j 2.0 M4 发布
    iBoxDB for .NET v1.5发布, 移动NoSQL数据库
    GNU libc (Glibc) 2.18 发布
    Android 开源项目维护者宣布退出
    Jeasyframe 开源框架 稳定版 V1.5 发布
    Spring Mobile 1.1.0.RC1 和 1.0.2 发布
    Deis logo 开源PaaS系统 Deis
    EasyCriteria 3.0 发布
    TypeScript 0.9.1 发布,新增 typeof 关键字
  • 原文地址:https://www.cnblogs.com/gocode/p/analysis-source-code-of-AtomicInteger.html
Copyright © 2011-2022 走看看