【Java 线程系列】CAS 原理解析

三、Jdk 中相关原子操作类的使用

===============================================================================

3.1、AtomicInteger


  • int addAndGet(int delta):以原子方式将输入的数值与实例中的值 (AtomicInteger 里的 value)相加,并返回结果。

  • boolean compareAndSet(int expect,int update):如果输入的数值等于预 期值,则以原子方式将该值设置为输入的值。

  • int getAndIncrement():以原子方式将当前值加 1,注意,这里返回的是自增前的值。

  • int getAndSet(int newValue):以原子方式设置为 newValue 的值,并返回旧值。

下面源码演示基本类型的原子操作类:


public class UseAtomicInt {

    static AtomicInteger ai = new AtomicInteger(10);



    public static void main(String[] args) {

        ai.getAndIncrement();



        ai.incrementAndGet();



        //ai.compareAndSet();

        ai.addAndGet(24);

        ai.getAndAdd(24);

    }

}





3.2、AtomicIntegerArray


主要是提供原子的方式更新数组里的整型,其常用方法如下。

  • int addAndGet(int i,int delta):以原子方式将输入值与数组中索引 i 的元 素相加。

  • boolean compareAndSet(int i,int expect,int update):如果当前值等于 预期值,则以原子方式将数组位置 i 的元素设置成 update 值。

需要注意的是,数组 value 通过构造方法传递进去,然后AtomicIntegerArray 会将当前数组复制一份,所以当 AtomicIntegerArray 对内部的数组元素进行修改 时,不会影响传入的数组。

3.3、更新引用类型


原子更新基本类型的 AtomicInteger,只能更新一个变量,如果要原子更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic 包提供了以下 3 个类。

3.3.1、AtomicReference

原子更新引用类型:


public class UseAtomicReference {

    static AtomicReference<UserInfo> atomicUserRef;

    public static void main(String[] args) {

        UserInfo user = new UserInfo("Mark", 15);//要修改的实体的实例

        atomicUserRef = new AtomicReference(user);

        UserInfo updateUser = new UserInfo("Bill",17);

        atomicUserRef.compareAndSet(user,updateUser);



        System.out.println(atomicUserRef.get());

        System.out.println(user);

    }

    

    //定义一个实体类

    static class UserInfo {

        private volatile String name;

        private int age;

        public UserInfo(String name, int age) {

            this.name = name;

            this.age = age;

        }

        public String getName() {

            return name;

        }

        public int getAge() {

            return age;

        }



        @Override

        public String toString() {

            return "UserInfo{" +

                    "name='" + name + '\'' +

                    ", age=" + age +

                    '}';

        }

    }



}





3.3.2、AtomicStampedReference

利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在 ABA 问题了。这就是 AtomicStampedReference 的解决方案。AtomicMarkableReference 跟 AtomicStampedReference 差不多,AtomicStampedReference 是使用 pair 的 int stamp 作为计数器使用,AtomicMarkableReference 的 pair 使用的是 boolean mark。 还是那个水的例子,AtomicStampedReference 可能关心的是动过几次, AtomicMarkableReference 关心的是有没有被人动过,方法都比较简单。


public class UseAtomicStampedReference {

    static AtomicStampedReference<String> asr

            = new AtomicStampedReference("mark",0);



    public static void main(String[] args) throws InterruptedException {

        //拿到当前的版本号(旧)

        final int oldStamp = asr.getStamp();

        final String oldReference = asr.getReference();

        System.out.println(oldReference+"============"+oldStamp);



        Thread rightStampThread = new Thread(new Runnable() {

            @Override

            public void run() {

                System.out.println(Thread.currentThread().getName()+":当前变量值:"

                        +oldReference + "-当前版本戳:" + oldStamp + "-"

                  + asr.compareAndSet(oldReference,

                        oldReference + "+Java", oldStamp,

                        oldStamp + 1));

            }

        });



        Thread errorStampThread = new Thread(new Runnable() {

            @Override

            public void run() {

                String reference = asr.getReference();

                System.out.println(Thread.currentThread().getName()

                        +":当前变量值:"

                        +reference + "-当前版本戳:" + asr.getStamp() + "-"

                        + asr.compareAndSet(reference,

                        reference + "+C", oldStamp,

                        oldStamp + 1));

            }

        });

        rightStampThread.start();

        rightStampThread.join();

        errorStampThread.start();

        errorStampThread.join();



        System.out.println(asr.getReference()+"============"+asr.getStamp());

    }

}





3.3.3、AtomicMarkableReference

AtomicMarkableReference:原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引 用类型。构造方法是 AtomicMarkableReference(V initialRef,booleaninitialMark)。

请添加图片描述

Java高频面试专题合集解析:

阿里Java岗面试百题:Spring 缓存 JVM 微服务 数据库 RabbitMQ等

当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!

阿里Java岗面试百题:Spring 缓存 JVM 微服务 数据库 RabbitMQ等

更多Java架构进阶资料展示

阿里Java岗面试百题:Spring 缓存 JVM 微服务 数据库 RabbitMQ等

阿里Java岗面试百题:Spring 缓存 JVM 微服务 数据库 RabbitMQ等

阿里Java岗面试百题:Spring 缓存 JVM 微服务 数据库 RabbitMQ等
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!

[外链图片转存中…(img-lMw7Fith-1721161178854)]

更多Java架构进阶资料展示

[外链图片转存中…(img-WrEZKFKR-1721161178854)]

[外链图片转存中…(img-c821wz7l-1721161178854)]

[外链图片转存中…(img-k1BGDUIb-1721161178855)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值