并发 - CAS 随手记
文章目录
前言
CAS是在JUC中,已经无处不在了,看过JUC源码的小伙伴可能都知道,原子操作类,一大堆,
不废话了,cas是一种无状态锁,即比较交换。
一、原理
一句话理解,复制拷贝,简单说,就是比较内存值和旧拷贝值,如果两者相等就 就把我们新的预期值给到内存值,就完了。
有啥缺点:
1.存在ABA问题,即线程1获取变量值为5,线程2将值改为10,线程3再将值改回5,那么对于1线程来说,是发现不了值变化过了。
ABA问题,可以通过加版本号,或者加时间戳的方式解决,如JUC并发包下AtomicMarkableReference 使用了boolean变量 ——表示引用变量是否被更改过,不关心中间变量变化了几次。
AtomicStampedReference通过用其中的构造方法中initialStamp(时间戳)用来唯一标识引用变量,引用变量中途被更改了几次,以此解决ABA问题。
2.还有一个比较深的问题,简单提一下
Cache miss问题,简单说,操作系统内存机制带来的问题,内存数据,要有缓存线概念,高速度缓存需要从缓存线中拿,比如CPU0 在对一个变量执行“比较并交换”(CAS)操作,而该变量所在的缓存线在 CPU7 的高速缓存中,这样就需要一个个个去找了。
3 长时间自旋带来的性能消耗
以JUC下AtomicLong为例,高并发场景下,假如线程一直无法进行CAS操作成功,内部是dowhile死循环,会一直自旋,消耗CPU。
提提Unsafe类
Unsafe是CAS核心类。我们知道,Java是无法直接访问底层操作系统,而是通过本地方法访问。JDK中Unsafe类,底层调用本地方法,提供硬件级别原子操作。
可以使用sun.misc.Unsafe包下。
Unsafe unsafe = Unsafe.getUnsafe();
调用
也可以通过反射获取Unsafe实例。
Field field = Unsafe.class.getDeclareField(“theUnsafe”);
field.setAccessible(true);
获取
还有其他的很多方式,工具类,不细说啦
热爱生活的码小子wmxiang:
工作之余,记录自己平时的一些小毛病,以及问题排查和解决方案思路。记录自己的经验和不足之处,笔记中可能会有很多不足之处,欢迎各位留言指正讨论。