CAS缺陷、JUC的atomic包及包中类(原子引用类)的基本介绍

CAS缺陷


CAS虽然高效地解决了原子操作,但是还是存在一些缺陷的 ,主要表现在三个方面:循环时间太长、只能保证一个共享变量原子操作、ABA问题。
循环时间太长
        如果CAS一直不成功呢?这种情况绝对有可能发生。如果自旋CAS长时间地不成功,则会给CPU带来非常大的开销。在JUC中有些地方就限制了CAS自旋的次数,例如BlockingQueue的SynchronousQueue,
只能保证一个共享变量原子操作
        看了CAS的实现就知道这只能针对一个共享变量,如果是多个共享变量就只能使用锁了。
ABA问题
        CAS需要检查操作值有没有发生改变,如果没有发生改变则更新。但是存在这样一种情况 :如果一个值原来是A,变成了B,然后又变成了A.那么在CAS检查的时候会发现没有改变,但是实质上它已经发生了改变,这就是所谓的ABA问题。

CAS的ABA隐患问题的解决

        对于ABA问题其解决方案是加上版本号。即在每个变量都加上一个版本号,每次改变时加1 ,即  A->B->A    变成 1A -> 2B -> 3A。

        Java提供了AtomicStampedReference(添加版本戳)来解决。AtomicstampedReference通过包装 [E, Integer] 的元组来对对象标记版本戳stamp ,从而避免ABA问题。对于上面的实例应该线程1会失败。


J.U.C之atomic包


atomic包介绍
        通过前面CAS的学习,我们了解到AtomicInteger的工作原理:它们的内部都维护者一个对应的基本类型的成员变量value ,这个变量是被volatile关键字修饰的,保证多线程环境下看见的是同一个(可见性) 。              AtomicInteger在进行一些原子操作的时候 ,依赖Unsafe类里面的CAS方法,原子操作就是通过自旋方式,不断地使用CAS函数进行尝试直到达到自己的目的。

        除了AtomicInteger类以外还有很多其他的类也有类似的功能,在JUC中有一个包java.util.concurrent.atomic存放原子操作的类, atomic里的类主要包括: 
            ●基本类型
                     使用原子的方式更新基本类型
                     AtomicInteger :整形原子类
                     AtomicLong :长整型原子类
                     AtomicBoolean :布尔型原子类

                         AtomicInteger主要API如下: 
                             get()//直接返回值
                             getAndAdd(int)//增加指定的数据,返回变化前的数据
                             getAndDecrement() //减少1 ,返回减少前的数据_
                             getAndIncrement() //增加1 ,返回增加前的数据
                             getAndSet(int)//设置指定的数据,返回设置前的数据
    
                             addAndGet(int)//增加指定的数据后返回增加后的数据
                             decrementAndGet() //减少1 ,返回减少后的值
                             incrementAndGet() //增加1 ,返回增加后的值
                             lazySet(int)//仅仅当get时才会set
                             compareAndSet(int, int)//尝试新增后对比 ,若增加成功则返回true否则返回false

                                 AtomicLong主要API和AtomicInteger ,只是类型不是int ,而是long

            ●引用类型
                     AtomicReference :引用类型原子类
                     AtomicStampedRerence :原子更新引用类型里的字段原子类
                     AtomicMarkableReference : 原子更新带有标记位的引用类型

            ●数组类型
                     使用原子的方式更新数组里的某个元素
                             AtomicIntegerArray :整形数组原子类
                             AtomicLongArray ;长整形数组原子类
                             AtomicReferenceArray :引用类型数组原子类

                             AtomicIntegerArray主要API如下:
                                     addAndGet(int, int)//执行加法,第一个参数为数组的下标, 第二个参数为增加的数量,返回增加后的结果
                                     compareAndSet(int, int, int)// 对比修改,参1数组下标,参2原始值,参3修改目标值,成功返回true否则false
                                     decrementAndGet(int)//参数为数组下标,将数组对应数字减少1,返回减少后的数据
                                     incrementAndGet(int)//参数为数组下标,将数组对应数字增加1,返回增加后的数据
                                     getAndAdd(int, int)// 和addAndGet类似,区别是返回值是变化前的数据
                                     getAndDecrement(int)//和decrementAndGet类似 ,区别是返回变化前的数据
                                     getAndIncrement(int)//和incrementAndGet类似 ,区别是返回变化前的数据
                                     getAndSet(int, int)// 将对应下标的数字设置为指定值,第二个参数为设置的值,返回是变化前的数据

                                         AtomicintegerArray主要API和AtomicLongArray ,只是类型不是int ,而是long

            ●对象的属性修改类型
                     AtomicIntegerFieldUpdater.原子更新整形字段的更新器
                             AtomicL ongFieldUpdater :原子更新长整形字段的更新器
                             AtomicStampedReference :原子更新带有版本号的引用类型。
            ●JDK1.8新增类
                     DoubleAdder :双浮点型原子类
                     LongAdder :长整型原子类
                     DoubleAccumulator :类似DoubleAdder ,但要更加灵活(要传入一个函数式接口)
                     LongAccumulator :类似LongAdder ,但要更加灵活(要传入-个函数式接口)
                虽然涉及到的类很多,但是原理和AtomicInteger都是一样,使用CAS进行的原子操作,其方法和使用都是大同小异的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值