CAS

AtomicInteger的原子性,底层用的为什么要用CAS而不是synchronized?

CAS的认识

CAS的全称为Compare-And-Swap,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。
CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。在执行过程中不允许被中断,不会造成数据不一致问题。
CAS:比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较知道主内存和工作内存中的值一致为止。
CAS应用:CAS有3个操作数,内存值V,旧的预期值A,要修改的更新值B。

AtomicInteger的底层代码

unsafe类中的所有方法都是native方法

//AtomicInteger
 public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
//valueOffset表示该变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的
    //unsafe.getAndAddInt
    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;
    }

CAS的缺点:

①循环时间长,开销大(如果CAS失败,会一直进行尝试,如果长时间一直不成功,可能会给CPU带来很大的开销。)

②只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原 子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作

③引出了ABA问题

原子引用AtomicReference:

class User{
    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    String userName;
    int age;

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}
public class AtomicReferenceDemo {

    public static void main(String[] args) {
        AtomicReference<User> userAtomicReference = new AtomicReference<>();
        User u1 = new User("zhangsan",22);
        User u2 = new User("lisi",20);
        userAtomicReference.set(u1);
        System.out.println(userAtomicReference.compareAndSet(u1,u2)+"\t"+userAtomicReference.get().toString());
        System.out.println(userAtomicReference.compareAndSet(u1,u2)+"\t"+userAtomicReference.get().toString());
    }
}

AtomicStampedReference版本号原子引用:ABA问题的解决

/**
 * ABA问题的解决
 */
public class AtomicStampedReferenceDemo {
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {

        /**
         * ABA问题的产生
         */
        new Thread(()->{
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"t1").start();

        new Thread(()->{
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicReference.compareAndSet(100,2019);
            System.out.println(atomicReference.get());
        },"t2").start();

        /**
         * ABA问题的解决
         */
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();
            try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
            atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
            stamp = atomicStampedReference.getStamp();
            atomicStampedReference.compareAndSet(101,100,stamp,stamp+1);
            System.out.println(atomicStampedReference.getStamp() + " =" + atomicStampedReference.getReference());
        },"t3").start();

        new Thread(()->{
            int stamp = atomicStampedReference.getStamp();
            try { TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); }
            boolean result = atomicStampedReference.compareAndSet(100,2019,stamp,stamp+1);
            System.out.println(result+" "+atomicStampedReference.getStamp()+ "=="+ atomicStampedReference.getReference());
        },"t4").start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值