Java源码阅读之:AtomicInteger

喜欢而已 提交于 2019-12-26 07:43:47

AtomicInteger源码分析

Top:带着问题看源码

在这周之前对原子类毫无了解,前面看了Unsafe类,对CAS操作有了一点了解。所以看AtomicInteger时的问题很简单,弄清楚它是什么类,有什么作用。

参考:

彤哥读源码
https://mp.weixin.qq.com/s/DdwSC5bYgFCWwnb0jxkspg

一:简介

AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作。

原子操作

原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。

原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。

我们这里说的原子操作与数据库ACID中的原子性,彤哥认为,数据库中的原子性主要运用在事务中,一个事务之内的所有更新操作要么都成功,要么都失败,事务是有回滚机制的,而这里说的原子操作是没有回滚的,这是最大的区别。

二:源码解析

总的来说,源码还是很简单的,很容易理解。提供原子操作主要是利用Unsafe类中的CAS方法。

属性

// 获取Unsafe实例    
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 标识value字段的偏移量,用来寻找
private static final long valueOffset;
// 静态代码块,通过unsafe获取value的偏移量
static {
   try {
       valueOffset = unsafe.objectFieldOffset
           (AtomicInteger.class.getDeclaredField("value"));
   } catch (Exception ex) { throw new Error(ex); }
}

// 存储int类型值的地方,使用volatile修饰
private volatile int value;

(1)使用int类型的value存储值,且使用volatile修饰,volatile主要是保证可见性,即一个线程修改对另一个线程立即可见,主要的实现原理是内存屏障,这里不展开来讲,有兴趣的可以自行查阅相关资料。

(2)调用Unsafe的objectFieldOffset()方法获取value字段在类中的偏移量,用于后面CAS操作时使用。

方法

构造方法和没有使用cas的get和set方法

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

    public AtomicInteger() {
    }

	public final int get() {
        return value;
    }

	public final void set(int newValue) {
        value = newValue;
    }

通过Unsafe实现的set方法

    // 调用putOrderedInt方法,有序写入,不保证原子性
	public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }
    // 最终通过CAS方法赋值
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    // 直接调用
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
	// 没看出来和上一个语句的差别
    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

自增自减以及加减的原子操作方法

	// 自增1,调用unsafe的getAndAddInt方法,而unsafe中这个方法是调用CAS方法完成。返回未增加1时的值
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    // 自减1,同上
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
    // 加上给定值,同上
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
	// 自增1,返回加1后的值
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    // 自减1,返回减1后的值
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
    // 加上一个值,返回操作后的值。
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

三:总结

(1)AtomicInteger中维护了一个使用volatile修饰的变量value,保证可见性;

(2)AtomicInteger中的主要方法最终几乎都会调用到Unsafe的compareAndSwapInt()方法保证对变量修改的原子性。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!