CAS记录

  首先介绍一下什么是CAS,CAS是乐观锁的一种,用于JAVA并发编程。CAS解读为compareAndSet,比较并设值。例如有一个AtomicBoolean a;

 public final boolean compareAndSet(boolean expect, boolean update) 

a.compareAndSet(boolean expect,boolean update) expect指得是期望值,update表示要更新为的值,当且仅当expect与此刻变量a的值是一样的时候才去改变。返回值就代表是否做了这次修改。
  当多个线程操作同一个共享资源时,仅能有一个线程同一时间获得锁成功,在乐观锁中,其他线程发现自己无法成功获得锁,并不会像悲观锁那样阻塞线程,而是直接返回,也可以去选择再次重试获得锁,也可以直接退出。这里说重现获取就比如AtomicBoolean的getAndSet方法

/**
     * Atomically sets to the given value and returns the previous value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final boolean getAndSet(boolean newValue) {
        boolean prev;
        do {
            prev = get();
        } while (!compareAndSet(prev, newValue));
        return prev;
    }

可以看到这里做了比较如果不等于期望值,就重新获取再次设值。这也叫做CAS的自旋。
直接返回就不说了,指的就是没有do while循环的场景。
 一般情况下我们不需要关心底层到底如何实现comareAndSet的,因为这牵涉到C层对硬件cpu指令的操作。我们只要知道CAS并不会使线程挂起,它一直处于用户态。其次我们还要了解一个lazySet方法。在使用atomicXXX ,例如AtomicBoolean,jvm会确保其他线程读取到最新值,原子类和voliatile变量也是一样的,这是由依赖于硬件的系统指令(如x86的xchg)实现的。lazySet却是无法保证这一点的方法,所以其他线程在之后的一小段时间里还是可以读到旧的值.可以把lazySet理解成普通的赋值操作。set方法直接对value操作,value是volatile类型,修改对其他线程可见。接下来分析一下atomic包都有啥
在这里插入图片描述

  • 原子类型基本类型:AtomicBoolean、AtomicInteger、AtomicLong。
    以上3个类提供的方法几乎一模一样,仅以AtomicInteger为例进行讲解,AtomicInteger的常用方法如下。
    int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。
    boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。❑ int getAndIncrement():以原子方式将当前值加1,注意,这里返回的是自增前的值。
    void lazySet(int newValue):最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。关于该方法的更多信息可以参考并发编程网翻译的一篇文章《AtomicLong.lazySet是如何工作的?》,文章地址是“http://ifeve.com/how-does-atomiclong-lazyset-work/”。
    int getAndSet(int newValue):以原子方式设置为newValue的值,并返回旧值。
    Atomic包提供了3种基本类型的原子更新,但是Java的基本类型里还有char、float和double等。那么问题来了,如何原子的更新其他的基本类型呢?
    可以通过两种方式:一种是想AtomicBoolean那样,封装转化,但是又局限性。另一种方式可以通过AtomicReferce来做。

  • 原子更新数组:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray.
    AtomicIntegerArray类主要是提供原子的方式更新数组里的整型,其常用方法如下:
    ➢int addAndGet(int i,int delta):以原子方式将输入值与数组中索引i的元素相加。➢boolean compareAndSet(int i,int expect,int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值。
    在这里插入图片描述
    需要注意的是,数组value通过构造方法传递进去,然后AtomicIntegerArray会将当前数组复制一份,所以当AtomicIntegerArray对内部的数组元素进行修改时,不会影响传入的数组。

  • 原子更新引用类AtomicReference

  • 在这里插入图片描述

  • 原子更新字段类
    ❑ AtomicIntegerFieldUpdater:原子更新整型的字段的更新器。
    ❑ AtomicLongFieldUpdater:原子更新长整型字段的更新器。
    ❑ AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题。
    要想原子地更新字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新类的字段(属性)必须使用public volatile修饰符。
    在这里插入图片描述
    以上内容大部分来自阅读《Java并发变成得艺术》,这里做个记录。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值