File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 2323## 乐观锁的基础 --- CAS
2424在乐观锁的实现中,我们必须要了解的一个概念:CAS。
2525
26- 什么是 CAS 呢? Compare-and-Swap,即** 比较并替换** 。
26+ 什么是 CAS 呢? Compare-and-Swap,即** 比较并替换** ,或者 ** 比较并设置 ** 。
2727
2828- 比较:读取到一个值 A,在将其更新为 B 之前,检查原值是否为 A(未被其它线程修改过,** 这里忽略 ABA 问题** )。
2929
@@ -129,10 +129,44 @@ class Test{
129129一旦有第二个线程加入** 锁竞争** ,偏向锁转换为** 轻量级锁** (** 自旋锁** )。锁竞争:如果多个线程轮流获取一个锁,但是每次获取的时候
130130都很顺利,没有发生阻塞,那么就不存在锁竞争。只有当某线程获取锁的时候,发现锁已经被占用,需要等待其释放,则说明发生了锁竞争。
131131
132- ## 可重入锁
132+ 在轻量级锁状态上继续锁竞争,没有抢到锁的线程进行** 自旋** 操作,即在一个循环中不停判断是否可以获取锁。获取锁的操作,就是通过 CAS 操
133+ 作修改对象头里的锁标志位。先** 比较** 当前锁标志位是否为** 释放** 状态,如果是,将其设置为** 锁定** 状态,比较并设置是原子性操作,这个
134+ 是 JVM 层面保证的。当前线程就算持有了锁,然后线程将当前锁的持有者信息改为自己。
135+
136+ 假如我们获取到锁的线程操作时间很长,比如会进行复杂的计算,数据量很大的网络传输等;那么其它等待锁的线程就会进入长时间的自旋操作,这个
137+ 过程是非常耗资源的。其实这时候相当于只有一个线程在有效地工作,其它的线程什么都干不了,在白白地消耗 CPU,这种现象叫做** 忙等
138+ (busy-waiting)** 。所以如果多个线程使用** 独占锁** ,但是没有发生锁竞争,或者发生了很轻微的锁竞争,那么 synchronized 就是轻量
139+ 级锁,允许短时间的忙等现象。这是一种择中的想法,** 短时间的忙等,换取线程在用户态和内核态之间切换的开销** 。
140+
141+ 显然,忙等是有限度的(JVM 有一个计数器记录自旋次数,默认允许循环 10 次,可以通过[ 虚拟机参数更改] ( #参数介绍 ) )。如果锁竞争情况严重,
142+ 达到某个最大自旋次数的线程,会将轻量级锁升级为重量级锁(依然是通过 CAS 修改锁标志位,但不修改持有锁的线程 ID)。当后续线程尝试获取
143+ 锁时,发现被占用的锁是重量级锁,则直接将自己挂起(而不是上面说的忙等,即不会自旋),等待释放锁的线程去唤醒。在 JDK1.6 之前, synchronized
144+ 直接加重量级锁,很明显现在通过一系列的优化过后,性能明显得到了提升。
145+
146+ JVM 中,synchronized 锁只能按照偏向锁、轻量级锁、重量级锁的顺序逐渐升级(也有把这个称为** 锁膨胀** 的过程),不允许降级。
147+
148+ ## 可重入锁(递归锁)
133149
134150## 公平锁和非公平锁
135151
152+ ## 参数介绍
153+
154+ -XX:-UseBiasedLocking=false 关闭偏向锁
155+
156+ ```
157+
158+ JDK1.6
159+
160+ -XX:+UseSpinning 开启自旋锁
161+
162+ -XX:PreBlockSpin=10 设置自旋次数
163+
164+ JDK1.7 之后 去掉此参数,由 JVM 控制
165+
166+
167+ ```
168+
169+
136170
137171
138172
You can’t perform that action at this time.
0 commit comments