CAS:保护共享资源的无锁实现
CAS
CompareAndSet,简称CAS(也有Compare And Swap的说法),它是原子的
它会将pre即之前的值和最新值进行比较,如果相同,修改为next,不同则修改失败
CAS的底层是lock cmpchg指令(X86架构),在单核和多核CPU下都能保证比较-交换是原子的
使用例子如下:
CAS与volatile
CAS需要volatile支持才能读取到共享变量的最新值实现比较并交换的效果
为什么无锁效率高?
无锁情况下,即使重试失败,线程也在不断运行,而synchronzied会让线程没有锁的时候停止运行,发生上下文切换,进入阻塞(上下文切换成本很高)。
要注意的是,无锁情况下,要保证CPU核心数多于线程数,避免cas线程分不到时间片,发生上下文切换,影响性能
适用场景:CPU核心数多于等于线程数
特点:CAS基于乐观锁的思想,synchronzied基于悲观锁的思想,CAS体现的是无锁并发,无阻塞
并发
CAS应用
原子整数
J.U.C并发包提供了
AtomicBoolean
AtomicInteger
AtomicLong
AtomicInteger方法如下:
updateAndGet原理:用接口的方法具体实现计算结果和cas操作实现
原子引用
原子引用可以使引用类型的变量也能进行cas操作,类型有: AtomicReference
AtomicMarkableReference AtomicStampedReference
AtomicReference例子如下
ABA问题:变量值从A修改为B再修改为A,cas操作仍能够执行成功可以给变量加上一个版本号
AtomicStampedReference(Stamped:时间戳,可以理解为版本号)应用如下
AtomicMarkableReference可以用来判断变量是否被修改过
应用:
原子数组
分为:
AtomicIntegerArray AtomicLongArray AtomicReferenceArray
supplier 提供者 ()-> (一个结果)
function 函数 (一个参数)->(一个结果)
consumer 消费者 (一个参数)-> ()
BiFunction (两个参数)-> (一个结果)
BiConsumer(两个参数)-> ()
原子更新器
字段更新器:
AtomicReferenceFieldUpdater AtomicIntegerFieldUpdater AtomicLongFieldUpdater
字段更新器可以针对对象的某个域(Field)进行原子操作,只能配合volatile修饰的字段使用,否则会出现异常
原子累加器
LongAdder,LongAccumulator是专门的累加类
相对于AtomicLong性能更高,因为LongAdder在有竞争时设置多个累加单元(线程1累加Cell[0],线程2累加Cell[1]...最后结果汇总,累加单元不会超过CPU核心数),减少了CAS重试失败的次数。
LongAdder原理
cas锁,不要用于实践,while(true)会一直运行,降低性能
关键的域:
底层实现:Unsafe
Unsafe对象提供了非常底层的,操作内存,线程的方法,unsafe方法不能直接调用,只能通过反射获得
获取:
unsafe通过内存偏移量定位到属性
unsafe通过获取到域的偏移地址,再进行cas操作修改值
unsafe模拟实现原子整数
原子整数,原子引用,原子数组,字段更新器,原子累加器底层都是用unsafe实现