在技术日新月异的今天,真正应该花费时间学习的是那些不变的编程思想,今天我们来接着上一篇文章来聊一下锁思想,我们上一篇”读写锁“详细的分析了读写锁解决线程饥饿的思想。那么今天我们再来聊另一个思想: 自旋。
提到自旋锁,很多Java开发者第一时间可能会想到CAS,因为CAS 其实是面试中的常客,而且在底层原理和我们实际应用中也是比较常出现的一种思想。比如: ConcurrentHashMap,原子类,Mysql乐观锁的实现等,我们接下来会详细的探讨。为了能说明问题,我们从以下几个问题由浅入深的来一一解答一下,在看之前自己也多思考思考为什么。
- 自旋和CAS分别是什么以及他俩的关系是什么?
- 什么时候会用到自旋锁及CAS呢?
- 自旋及CAS的优点及缺点是什么?
自旋和CAS分别是什么以及他俩的关系是什么?
我们简单的来解释一下这两个都是啥意思以及他们之间的关系
自旋
首先,我们来看一下什么叫自旋?顾名思义,自旋可以理解为“自我旋转”,放到程序中就是"自我循环",比如while循环或者for循环。结合着锁来理解的话就是,先获取一次锁,如果获取不到锁,会不停的循环获取,直到获取到。不像普通的锁那样,如果获取不到锁就进入阻塞状态。
自旋和非自旋的获取锁的流程
我们来看一下自旋锁和非自旋锁的获取锁的过程
可以看到,自旋锁没获取到锁并不会释放CPU时间片,而是通过自旋等待锁的释放,也就是说,它会一直尝试获取锁,如果获取失败就再次尝试,直到成功为止。
CAS
CAS 是什么,它的英文全称是 Compare-And-Swap,中文叫做“比较并交换”,它是一种思想、一种算法。
CAS算法有3个基本操作数:
- 内存地址V
- 旧的预期值A
- 要修改的新值B
在并发场景下,各个代码的执行顺序不能确定,为了保证并发安全,我们可以使用普通的互斥锁,比如Java的 synchronized, ReentrantLock等。而CAS的特点是避免使用互斥锁,当多个线程并发使用CAS更新同一个变量时,只有一个可以操作成功,其他都会失败。而且用CAS更新失败的线程并不会阻塞,会快速失败并返回一个失败的状态,允许你再次尝试。
自旋锁和CAS的关系是啥
其实他们是两个不同的概念
自旋是一种锁优化的机制,在锁优化中『自旋锁』指线程空转重试获取锁,避免线程上下文切换带来的开销。
CAS是一种乐观锁机制,cas是通过比较并交换,失败的时候可以直接返回false不用自旋的获取。只是一般应用场景下,cas都会带有重试机制(while或者for实现空转,不断尝试获取)。
如果非要加个关系的话 自旋锁 = 循环+CAS。
什么时候会用到自旋锁及CAS呢?
在一般并发场景下,加普通锁基本可以解决所有的安全问题,但是为什么还分各种锁,悲观/乐观&#