CAS 原子操作(Atomic)

CAS 原子操作: 不可分割的操作

CAS 原理

CAS(Compare And Swap),指令级别保证这是一个原子操作

三个运算符:  一个内存地址V,一个期望的值A,一个新值B

基本思路:如果地址V上的值和期望的值A相等,就给地址V赋给新值B,如果不是,不做任何操作。

循环(死循环,自旋)里不断的进行CAS操作

 

CAS存在的问题

ABA问题:

同时有2个线程获取当前变量值,均为A,当第一个线程对该变量进行2次操作A->B->A.此时对于另外一个线程表现出的现象为此值并未改变,并对该值进行操作。这样就出现了ABA问题。

解决的方法:

给该值添加一个版本号,每一次的操作都会修改版本号,只有修改时版本号与预期版本号相同时,才会操作成功。

CPU消耗

因为CAS操作如果不成功,将会循环进行CAS操作,则对CPU消耗过大

 

JAVA中的Atomic类

 Atomic类的主要公共方法:

boolean compareAndSet(expect, update) 修改值,参数为预期值和更新的值.但此方法只会执行一次,成功返回true,失败返回false,自旋更新会使用该方法实现

xxx getAndSet(xxx) 赋值,如果失败,会自旋更新

AtomicInteger

public class AtomicIntegerDemo {
    static AtomicInteger count = new AtomicInteger(10);

    public static void main(String[] args) {
        System.out.println(count.getAndIncrement());//(自旋)先获得该值,后+1
        System.out.println(count.incrementAndGet());//(自旋)先+1,在获得该值
        System.out.println(count.get());
    }
}

运行结果:

10
12
12

AtomicReference

public class AtomicReferenceDemo {
    static AtomicReference<User> reference = new AtomicReference<>();

    public static void main(String[] args) {
        User user = new User("lb",18);
        reference.set(user);//赋值
        User user1 = new User("ll",20);
        reference.compareAndSet(user,user1);
        System.out.println(reference.get());
        User user2 = new User("bb",22);
        reference.getAndSet(user2);
        System.out.println(reference.get());
    }


    static class User{
        private String name;
        private int age;

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

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

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

AtomicStampedReference

带版本号的Atomic引用类

public class AtomicStampedReferenceDemo {
    //設置初始值,初始版本号
    static AtomicStampedReference<String> reference = new AtomicStampedReference<>("lb", 0);

    public static void main(String[] args) throws InterruptedException {
        String init_name = reference.getReference();
        int init_stamp = reference.getStamp();
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                System.out.println("修改前的name="+init_name+",版本:"+init_stamp
                        +".修改的结果:"+reference.compareAndSet(init_name,init_name+"_java",init_stamp,init_stamp+1));

            }
        };

        Thread thread2 = new Thread(){
            @Override
            public void run() {
                String name = reference.getReference();
                System.out.println("修改前的name="+name+",版本:"+init_stamp
                        +".修改的结果:"+reference.compareAndSet(init_name,name+"_C",init_stamp,init_stamp+1));

            }
        };
        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();
        System.out.println("最终: name="+reference.getReference()+",版本:"+reference.getStamp());
    }
}

运行结果:

修改前的name=lb,版本:0.修改的结果:true
修改前的name=lb_java,版本:0.修改的结果:false
最终: name=lb_java,版本:1

注意:

AtomicMarkableReference,boolean 有没有动过

AtomicStampedReference  动过几次

AtomicIntegerArray

 

public class AtomicIntegerArrayDemo {
    static int[] arr = new int[]{2,1};
    static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);

    public static void main(String[] args) {
        System.out.println(atomicIntegerArray.get(0));//参数为下标
        atomicIntegerArray.set(0,3);
        System.out.println(atomicIntegerArray.get(0));
        System.out.println(arr[0]);
    }
}

运行结果:修改的值是AtomicIntegerArray中存储的副本,而不是数组本身

2
3
2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值