AtomicInteger CAS分析

AtomicInteger count = new AtomicInteger(0);

count.incrementAndGet();

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

// var1 AtomicInteger对象
// var2 地址偏移量
// var3 增加量
public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            // 获取该var1对象的var2地址的值
            var5 = this.getIntVolatile(var1, var2);
            // 如果var2的值跟var5的值相等,则进行+1
            // 否则则进行重试
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

模拟场景:A线程和B线程同时进行自增,假设初始值为1,两个线程进行自增,要求结果=3

1. A线程先拿到值 var5 = this.getIntVolatile(var1, var2) = 1,接着要进行自增时,让出了CPU即由B执行

2. 由于A还没自增就让出了CPU,所以B线程拿到的var5还是1,接着执行自增逻辑,比较var5的值和地址偏移量var2里的值是否一致,结果都等于1,所以将var5的值+1,B线程结束,让出CPU,此时值为2.

3. A线程重新拿到CPU,此时A线程里的var5还是1,进行自增时,偏移量var2的值已被B线程更改为2,所以进行比较时var5=1与var2=2的值不相等,自增失败返回false,此时再次进行重试,由于此时只有A线程在操作,就会像步骤2一样自增成功。

优点:通过这种轮训方式去自增,不会像加锁一样阻塞线程。

缺点:三个线程,A增,B增,C减。

A先拿到值,B先完成自增,接着C再完成自减,最后A再完成自增。

猜你喜欢

转载自blog.csdn.net/sosmmh/article/details/85214226
今日推荐