Skip to content

Commit a96254c

Browse files
committed
update readme in lock.
1 parent 414ebf6 commit a96254c

1 file changed

Lines changed: 36 additions & 2 deletions

File tree

lock/README.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
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

0 commit comments

Comments
 (0)