• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

简单分析AtomicInteger中的addAndget方法

开发技术 开发技术 2周前 (04-08) 9次浏览

简单使用AtomicInteger

首先贴出以下的代码,简单的使用AtomicInteger这个类来实现+1的操作。

import java.util.concurrent.atomic.AtomicInteger;

public class CASTest {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(10);

        for (int i = 0; i < 10; i ++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    atomicInteger.addAndGet(1);
                }
            }).start();
        }

        System.out.println(atomicInteger);
    }
}

打印的值是20,可见是线程安全的。以下逐步分析其中蕴含的CAS原理。

提供增加操作的addAndGet方法

分析其中的addAndGet方法,其源码如下

public final int addAndGet(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}

发现它是调用unsafe包的方法,首先对传给unsafe的getAnddAddInt的参数进行说明:

  • this指当前的AtomicInteger对象
  • valueOffset由AtmoicInteger类中的静态代码块确定,指的是AtomicInteger的value属性在内存中的偏移量
  • delta即要value值要改变的大小

实际执行修改操作的getAndAddInt方法

再来看unsafe包中的getAndAddInt的方法,为cas原理的核心方法

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

这个方法返回的值其实是修改前的值,所以addAndGet方法返回的是改方法的返回值 + delta
主要有以下步骤:

  1. do循环中通过getIntVolatile本地方法来获取主存中的Atomic的value值,并赋值给局部变量v
  2. compareAndSwapInt来同样通过o,offset参数来获取主存中的value值,代码中并未体现
  3. 通过比较v与compareAndSwapInt方法中再次获得的值来判断修改是否执行,即v = v + delta操作
  4. 成功则跳出循环,返回修改前的值
  5. 不成功则一直循环,自旋在此处

简单分析AtomicInteger中的addAndget方法

其他方法

其中getIntVolatile与compareAndSwapInt方法签名如下

//** Volatile version of {@link #getInt(Object, long)}  
public native int getIntVolatile(Object o, long offset);

//Atomically update Java variable to x if it is currently holding expected.Returns:true if successful
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

CAS的缺点

可以看到CAS原理其中是不断比较最初的值,和要进行修改时的值进行比较,来判断是否有其他线程修改了此变量;如果变量被修改,则不会继续修改变量。但是CAS是一种自旋的操作,会占用CPU的时间块分配的。以及存在这样一个逻辑漏洞:如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?如果在这段期间它的值曾经被改成了B,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个漏洞称为CAS操作的”ABA”问题。


程序员灯塔
转载请注明原文链接:简单分析AtomicInteger中的addAndget方法
喜欢 (0)