JAVA基础之AtomicInteger

概述

AtomicInteger底层同步CAS就是一种乐观锁思想的应用,采用CAS算法实现原子性运算。
并发和并行的区别:

  • 并发 通过CPU的调度,切换时间片,就算只有一个核心,也可以实现“同时做很多事情”
  • 并行 同一时刻,执行不同的任务,重点是同一时刻

方法

  • incrementAndGet() 原子性的加1,并返回加1后的值,先加再get
  • getAndIncrement() 原子性的加1,返回的是加1之前的值,这两个方法类似i++和++i
  • decrementAndGet() ,getAndDecrement() 原子性减1,返回方式同上
  • getAndAdd(int delta) ,addAndGet(int delta) 原子性加delta,返回方式同上
  • compareAndSet(int expect, int update) 如果传入的expect等于atomicInteger现有的值,就将atomicInteger改为update

源码解析

基于1.8,incrementAndGet()方法调用的是unsafe的getAndAddInt(),返回值是getAndAddInt+1,刚方法每次从内存中读取数据然后将此数据和 +1 后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止,而native方法 compareAndSwapInt是借助C来调用CPU底层指令实现的(多核lock)

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

关于unsafe的类可以如下测试:

private volatile int value;

 Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        valueOffset = unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("value"));
        System.out.println(unsafe.getAndAddInt(this, valueOffset, 1));
        System.out.println(unsafe.getAndAddInt(this, valueOffset, 1));

输出 0 1

unsafe.getAndAddInt() ,这个方法会比较当前值是否相等,然后设置为newValue

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;
    }
    
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

示例

int num =0;
AtomicInteger atomicInteger = new AtomicInteger();

ExecutorService service = BasicThreadFactory.getExecutorService();
        CountDownLatch countDownLatch = new CountDownLatch(10000);
        for(int i=0;i<10000;i++){
            service.submit(()->{
                num++;
                atomicInteger.incrementAndGet();
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        service.shutdown();
        System.out.println("res = " + num);
        System.out.println("atomic = " + atomicInteger.get());

在这里插入图片描述
输出结果,atomic =10000,res不总是等于10000

如何避免ABA

如果value的值先由A变成B,再由B变成A,虽然结果是正确的,但是过程是有问题的。
一个解决方法:使用atomicStampedReference 不仅判断值是否相等,还要判断版本号,AtomicStampedReference 还可以存储string,这样的话,可以将多个变量拼接存储

String str = "abc";
AtomicStampedReference atomicStampedReference = new AtomicStampedReference(str,1);
atomicStampedReference.compareAndSet(str, "abcd", 1, 2);
缺点
  • 如果CAS不成功,会一直占用cpu资源
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值