并发编程 — 原子类 AtomicInteger 详解

目录

 

一、AtomicInteger的基本用法

1、创建AtomicInteger

2、常用方法说明

2.1、自增方法

2.2、自减方法

2.3、原子性的更新值 

2.4、其他方法

3、AtomicInteger内幕

3.1、compareAndSwapInt 源码分析

 3.2、getAndAddInt 自旋方法

四、总结


一、AtomicInteger的基本用法

AtomicInteger与int的引用类型Integer继承Number类一样,AtomicInteger也是Number类的一个子类,除此之外,AtomicInteger还提供了很多原子性的操作方法。在AtomicInteger的内部有一个被volatile关键字修饰的成员变量value,实际上,AtomicInteger所提供的所有方法主要都是针对该变量value进行的操作。

1、创建AtomicInteger

AtomicInteger类提供了AtomicInteger() 和 AtomicInteger(int initialValue) 两个构造方法,有参数的可以指定一个初始值,无参的构造方法默认值为0,相当于 AtomicInteger( 0 )。

2、常用方法说明

2.1、自增方法

  • int getAndIncrement():返回当前 int 类型的value值,然后对value进行自增运算,该操作方法能够确保对value的原子性增量操作。
  • int incrementAndGet():直接返回自增后的结果,该操作方法能够确保对value的原子性增量操作。
	public static void main(String[] args) {
		
		AtomicInteger count = new AtomicInteger(2);
		
		// 先返回旧值,然后自增
		System.out.println("返回值:" + count.getAndIncrement());
	    //返回当前值
		System.out.println("当前值:" + count.get());
		
		//直接返回自增后的结果
		System.out.println("返回值:" + count.incrementAndGet());
		System.out.println("当前值:" + count.get());
		
	}

2.2、自减方法

  • int getAndDecrement():返回当前int类型的value值,然后对value进行自减运算,该操作方法能够确保对value的原子性减量操作。
  • int decrementAndGet():直接返回自减后的结果,该操作方法能够确保对value的原子性减量操作。
	public static void main(String[] args) {
		
		AtomicInteger count = new AtomicInteger(2);
		
		// 先返回旧值,然后自减
		System.out.println("返回值:" + count.getAndDecrement());
	    //返回当前值
		System.out.println("当前值:" + count.get());
		
		//直接返回自减后的结果
		System.out.println("返回值:" + count.decrementAndGet());
		System.out.println("当前值:" + count.get());
		
	}

2.3、原子性的更新值 

  • boolean compareAndSet(int expect, int update):原子性地更新AtomicInteger的值,其中expect代表当前的AtomicInteger数值,update则是需要设置的新值,该方法会返回一个boolean的结果:当expect和AtomicInteger的当前值不相等时,修改会失败,返回值为false;若修改成功则会返回true。
  • int getAndAdd(int delta):原子性地更新AtomicInteger 的value值,更新后的value为value和delta之和,方法的返回值为value的前一个值,该方法实际上是基于自旋+CAS算法实现的(Compare And Swap)原子性操作。
  • int addAndGet(int delta):该方法与getAndAdd(int delta)一样,也是原子性地更新AtomicInteger的value值,更新后的结果value为value和delta之和,但是该方法会立即返回更新后的value值。

2.4、其他方法

  • void set(int newValue):为AtomicInteger的value设置一个新值,通过对前面内容的学习,我们知道在AtomicInteger中有一个被volatile关键字修饰的value成员属性,因此调用set方法为value设置新值后其他线程就会立即看见。
  • void lazySet(int newValue):set方法修改被volatile关键字修饰的value值会被强制刷新到主内存中,从而立即被其他线程看到,这一切都应该归功于volatile关键字底层的内存屏障。内存屏障虽然足够轻量,但是毕竟还是会带来性能上的开销,比如,在单线程中对AtomicInteger的value进行修改时没有必要保留内存屏障,而value又是被volatile关键字修饰的,这似乎是无法调和的矛盾。幸好追求性能极致的JVM开发者们早就考虑到了这一点,lazySet方法的作用正在于此。
  • int get():返回AtomicInteger的value当前值。

3、AtomicInteger内幕

看看 AtomicInteger 类的内部原理,以更加深入地了解 AtomicInteger 的内幕。

// setup to use Unsafe.compareAndSwapInt for updates
    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;

上面是 AtomicInteger 类的代码片段,我们看到 类中 主要有 一个量静态变量 Unsafe unsaf 和 volatile 修饰 的 int value 变量。AtomicInteger 内部也只要是通过Unsafe 类操作 value 变量来完成原子操作的。

3.1、compareAndSwapInt 源码分析

我们看下在 AtomicInteger 类内部的 compareAndSet 方法内部调用的就是 Unsafe 类的 compareAndSwapInt 方法。

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

在 《CAS 原理》 一章中介绍过 CAS 操作包含三个三个参数分别为:内存值V、旧的预期值A、要修改的新值B,当且仅当预期值A与内存值V相等时,将内存值V修改为B,否则什么都不需要做。compareAndSwapInt 方法是一个 native 方法,其提供了CAS(Compare AndSwap)算法的实现,AtomicInteger类中的原子性方法几乎都借助于该方法实现。

 3.2、getAndAddInt 自旋方法

由于compareAndSwapInt方法的乐观锁特性,会存在对value修改失败的情况,但是有些时候对value的更新必须要成功,比如调用incrementAndGet、addAndGet等方法,本节就来分析一下addAndGet方法的实现。

 public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2); // 1
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); // 2

        return var5;
    }
  • 在 getAndAddInt 方法中有一个知道型 do .. while 循环语句,首先在注释 1 处获取当前被 volatile 关键字修饰的 value 值。
  • 在 注释 2 处执行 compareAndSwapInt 方法如果执行成功则返回,如果执行失败则再次执行下一轮的 compareAndSwapInt 方法,直到成功。

四、总结

AtomicInteger 提供了一个原子性的操作,其内部是通过调用 Unsafe 类提供的 native 方法通过 CAS 操作实现的。在某些方法中更是通过 自旋 + CAS 的方式实现的更新操作。

 

你可能感兴趣的:(并发编程,多线程,原子类,AtomicInteger)