该文章为面试精华版,如果是初学者,建议学习专栏:Java并发专栏
一、CAS原理及缺陷
原理:
-
CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。
-
更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。
-
从思想上来说,Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。
-
CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。
缺点:
- 在竞争激烈的时候,CPU开销较大
在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。
- 不能保证代码块的原子性
CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证多个变量共同进行原子性的更新,就不得不使用Synchronized了
二、ABA问题及解决
什么是ABA?
CAS的机制是在赋值的时候进行比较,如果此时的数值没有修改,则可以完成修改
但是,如果一个对象或者变量出现了:A => B => ...... => A
,此时CAS算法进行比较,会没有任何问题,进行修改。但是此时可能已经被修改过了无数次,其他线程的修改就丢失了,在复杂的数据结构比如链表,队列,栈、树等都可能出现不可预知的问题
解决方式–AtomicStampedReference
- 加一个版本号,除了比较对象值,还需要比较状态戳,类似于时间戳
- 每次修改成功也会同时修改状态戳
三、atomic类
在高并发条件下,如果都需要对一些基本类型进行修改,就会破坏其原子性
Java并发包提供了一个原子类,基于的是用了 Unsafe 类的 CAS 操作
主要分为基本类型 、数组类型、引用类型和对象的属性子四类
四、Unsafe类
很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Cassandra、Hadoop、Kafka等。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。
Java和C++语言的一个重要区别就是Java中我们无法直接操作一块内存区域,不能像C++中那样可以自己申请内存和释放内存。Java中的Unsafe类为我们提供了类似C++手动管理内存的能力,同时也有了指针的问题。