关于AtomicInteger的实现原理

首先给出一个并发编程时,对于计数器进行累加时有问题的程序:

public class CountExample1 {
    //  请求总数
    public static int clientTotal = 5000;
    // 同时并发执行的线程数
    public static int threadTotal = 200;
    public static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i< clientTotal; i ++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);

    }

    private static void add() {
        count ++;
    }
}

上述代码,本意是运行之后,count的值为5000,实际上每次运行的结果都小于5000。
改进:
将上述的int改为AtomicInteger,如下:
public class CountExample2 {
    //  请求总数
    public static int clientTotal = 5000;
    // 同时并发执行的线程数
    public static int threadTotal = 200;
    public static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i< clientTotal; i ++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }
    private static void add() {
        count.incrementAndGet();
    }
}
删除代码中每次执行的结果都是5000,与我们预期的一致。
那么AtomicInteger的实现原理是什么呢?
查看count.incrementAndGet()函数的实现,如下:
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
这个unsafe类提供的getAndAddInt(Object var1, long var2, int var4),查看该源码为:
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    return var5;
}
分析上述方法:
var5通过获取本地中的变量(其实应该取的是 主存的值),然后比较当前的var2的值与本地变量var5是否相等,如果不相等则重复判断,直到相等才执行增加操作。这样就保证数据的一致性。这个也叫做CMS。

猜你喜欢

转载自blog.csdn.net/timchen525/article/details/80369734