Skip to content

Commit e36ac97

Browse files
committed
重入锁
1 parent 521a586 commit e36ac97

File tree

1 file changed

+72
-2
lines changed

1 file changed

+72
-2
lines changed

MD/ReentrantLock.md

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ ReentrantLock 分为**公平锁**和**非公平锁**,可以通过构造方法
104104

105105

106106
#### 写入队列
107-
如果 `tryAcquire(arg)` 获取锁失败,则需要用 `acquireQueued(addWaiter(Node.EXCLUSIVE), arg)` 将当前线程写入队列中。
107+
如果 `tryAcquire(arg)` 获取锁失败,则需要用 `addWaiter(Node.EXCLUSIVE)` 将当前线程写入队列中。
108108

109109
写入之前需要将当前线程包装为一个 `Node` 对象(`addWaiter(Node.EXCLUSIVE)`)。
110110

@@ -153,6 +153,76 @@ ReentrantLock 分为**公平锁**和**非公平锁**,可以通过构造方法
153153

154154
这个处理逻辑就相当于自旋加上 `CAS` 保证一定写入队列。
155155

156+
#### 挂起等待线程
157+
158+
写入队列之后需要将当前线程挂起(利用`acquireQueued(addWaiter(Node.EXCLUSIVE), arg)`):
159+
160+
```java
161+
final boolean acquireQueued(final Node node, int arg) {
162+
boolean failed = true;
163+
try {
164+
boolean interrupted = false;
165+
for (;;) {
166+
final Node p = node.predecessor();
167+
if (p == head && tryAcquire(arg)) {
168+
setHead(node);
169+
p.next = null; // help GC
170+
failed = false;
171+
return interrupted;
172+
}
173+
if (shouldParkAfterFailedAcquire(p, node) &&
174+
parkAndCheckInterrupt())
175+
interrupted = true;
176+
}
177+
} finally {
178+
if (failed)
179+
cancelAcquire(node);
180+
}
181+
}
182+
```
183+
184+
首先会根据 `node.predecessor()` 获取到上一个节点是否为头节点,如果是则尝试获取一次锁。
185+
186+
如果不是头节点,或者获取锁失败,则会根据上一个节点的 `waitStatus` 来处理(`shouldParkAfterFailedAcquire(p, node)`)。
187+
188+
`waitStatus` 用于记录当前节点的状态,如节点取消、节点等待等。
189+
190+
`shouldParkAfterFailedAcquire(p, node)` 返回当前线程是否需要挂起,如果需要则调用 `parkAndCheckInterrupt()`
191+
192+
```java
193+
private final boolean parkAndCheckInterrupt() {
194+
LockSupport.park(this);
195+
return Thread.interrupted();
196+
}
197+
```
198+
199+
他是利用 `LockSupport``part` 方法来挂起当前线程的,直到被唤醒。
200+
201+
202+
### 非公平锁获取锁
203+
公平锁与非公平锁的差异主要在获取锁:
204+
205+
公平锁就相当于买票,后来的人需要排到队尾依次买票,不能插队。
206+
207+
而非公平锁则没有这些规则,是**抢占模式**,每来一个人不会去管队列如何,直接尝试获取锁。
208+
209+
非公平锁:
210+
```java
211+
final void lock() {
212+
//直接尝试获取锁
213+
if (compareAndSetState(0, 1))
214+
setExclusiveOwnerThread(Thread.currentThread());
215+
else
216+
acquire(1);
217+
}
218+
```
219+
220+
公平锁:
221+
```java
222+
final void lock() {
223+
acquire(1);
224+
}
225+
```
226+
156227

157228

158-

0 commit comments

Comments
 (0)