Skip to content

Commit fea6af8

Browse files
committed
📝 Writing docs.
1 parent 1856b94 commit fea6af8

File tree

2 files changed

+68
-568
lines changed

2 files changed

+68
-568
lines changed

docs/concurrent/Java锁.md

Lines changed: 68 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,40 @@ tags:
1616
<!-- TOC depthFrom:2 depthTo:4 -->
1717

1818
- [概述](#概述)
19-
- [概念](#概念)
20-
- [公平锁/非公平锁](#公平锁非公平锁)
21-
- [可重入锁](#可重入锁)
22-
- [独享锁/共享锁](#独享锁共享锁)
23-
- [互斥锁/读写锁](#互斥锁读写锁)
24-
- [乐观锁/悲观锁](#乐观锁悲观锁)
25-
- [分段锁](#分段锁)
26-
- [偏向锁/轻量级锁/重量级锁](#偏向锁轻量级锁重量级锁)
27-
- [自旋锁](#自旋锁)
28-
- [为什么用 Lock、ReadWriteLock](#为什么用-lockreadwritelock)
19+
- [概念](#概念)
20+
- [公平锁/非公平锁](#公平锁非公平锁)
21+
- [可重入锁](#可重入锁)
22+
- [独享锁/共享锁](#独享锁共享锁)
23+
- [互斥锁/读写锁](#互斥锁读写锁)
24+
- [乐观锁/悲观锁](#乐观锁悲观锁)
25+
- [分段锁](#分段锁)
26+
- [偏向锁/轻量级锁/重量级锁](#偏向锁轻量级锁重量级锁)
27+
- [自旋锁](#自旋锁)
28+
- [为什么用 Lock、ReadWriteLock](#为什么用-lockreadwritelock)
2929
- [Lock 和 ReentrantLock](#lock-和-reentrantlock)
30-
- [要点](#要点)
31-
- [源码](#源码)
32-
- [Lock](#lock)
33-
- [ReentrantLock](#reentrantlock)
34-
- [示例](#示例)
30+
- [要点](#要点)
31+
- [源码](#源码)
32+
- [Lock 接口定义](#lock-接口定义)
33+
- [ReentrantLock 属性和方法](#reentrantlock-属性和方法)
34+
- [Sync](#sync)
35+
- [示例](#示例)
3536
- [ReadWriteLock 和 ReentrantReadWriteLock](#readwritelock-和-reentrantreadwritelock)
36-
- [要点](#要点-1)
37-
- [源码](#源码-1)
38-
- [ReadWriteLock](#readwritelock)
39-
- [示例](#示例-1)
37+
- [要点](#要点-1)
38+
- [源码](#源码-1)
39+
- [ReadWriteLock 接口定义](#readwritelock-接口定义)
40+
- [示例](#示例-1)
4041
- [AQS](#aqs)
41-
- [要点](#要点-2)
42-
- [源码](#源码-2)
43-
- [同步队列](#同步队列)
44-
- [获取独占锁](#获取独占锁)
45-
- [释放独占锁](#释放独占锁)
46-
- [获取可中断的独占锁](#获取可中断的独占锁)
47-
- [获取超时等待式的独占锁](#获取超时等待式的独占锁)
48-
- [获取共享锁](#获取共享锁)
49-
- [释放共享锁](#释放共享锁)
50-
- [获取可中断的共享锁](#获取可中断的共享锁)
51-
- [获取超时等待式的共享锁](#获取超时等待式的共享锁)
42+
- [要点](#要点-2)
43+
- [源码](#源码-2)
44+
- [同步队列](#同步队列)
45+
- [获取独占锁](#获取独占锁)
46+
- [释放独占锁](#释放独占锁)
47+
- [获取可中断的独占锁](#获取可中断的独占锁)
48+
- [获取超时等待式的独占锁](#获取超时等待式的独占锁)
49+
- [获取共享锁](#获取共享锁)
50+
- [释放共享锁](#释放共享锁)
51+
- [获取可中断的共享锁](#获取可中断的共享锁)
52+
- [获取超时等待式的共享锁](#获取超时等待式的共享锁)
5253
- [资料](#资料)
5354

5455
<!-- /TOC -->
@@ -145,85 +146,65 @@ synchronized void setB() throws Exception{
145146

146147
### 要点
147148

148-
ReentrantLock 实现了 Lock 接口,所以支持 Lock 的所有方法。
149+
如果采用 Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用 Lock 必须在 try catch 块中进行,并且将释放锁的操作放在 finally 块中进行,以保证锁一定被被释放,防止死锁的发生。
150+
151+
`lock()` 方法的作用是获取锁。如果锁已被其他线程获取,则进行等待。
152+
153+
`tryLock()` 方法的作用是尝试获取锁,如果成功,则返回 true;如果失败(即锁已被其他线程获取),则返回 false。也就是说,这个方法无论如何都会立即返回,获取不到锁时不会一直等待。
154+
155+
`tryLock(long time, TimeUnit unit)` 方法和 `tryLock()` 方法是类似的,区别仅在于这个方法在获取不到锁时会等待一定的时间,在时间期限之内如果还获取不到锁,就返回 false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回 true。
156+
157+
`lockInterruptibly()` 方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过 `lock.lockInterruptibly()` 想获取某个锁时,假若此时线程 A 获取到了锁,而线程 B 只有在等待,那么对线程 B 调用 `threadB.interrupt()` 方法能够中断线程 B 的等待过程。由于 `lockInterruptibly()` 的声明中抛出了异常,所以 `lock.lockInterruptibly()` 必须放在 try 块中或者在调用 `lockInterruptibly()` 的方法外声明抛出 `InterruptedException`
158+
159+
> 注意:当一个线程获取了锁之后,是不会被 interrupt() 方法中断的。因为本身在前面的文章中讲过单独调用 interrupt() 方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。因此当通过 lockInterruptibly() 方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。
160+
161+
`unlock()` 方法的作用是释放锁。
162+
163+
ReentrantLock 是唯一实现了 Lock 接口的类。
149164

150165
ReentrantLock 字面意为可重入锁。
151166

152167
### 源码
153168

154-
#### Lock
169+
#### Lock 接口定义
155170

156171
```java
157172
public interface Lock {
158-
/** 获取锁,如果锁已被其他线程获取,则进行等待。 */
159173
void lock();
160-
/**
161-
* 获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。
162-
* 当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,
163-
* 而线程B只有在等待,那么对线程B调用threadB.interrupt()* 方法能够中断线程B的等待过程。
164-
*/
165174
void lockInterruptibly() throws InterruptedException;
166-
/**
167-
* tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回 true。
168-
* 如果获取失败(即锁已被其他线程获取),则返回 false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
169-
*/
170175
boolean tryLock();
171-
/**
172-
* 这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
173-
* 如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
174-
*/
175176
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
176-
/** 释放锁 */
177177
void unlock();
178-
/**
179-
* 返回绑定到此Lock实例的新的Condition实例。
180-
* 在等待条件之前,锁必须由当前线程保持。对 Condition.await 的调用将在等待之前以原子方式释放锁,
181-
* 并在等待返回之前重新获取锁。
182-
*/
183178
Condition newCondition();
184179
}
185180
```
186181

187-
#### ReentrantLock
188-
189-
##### Sync
182+
#### ReentrantLock 属性和方法
190183

191-
* `Sync` 这个类是 `ReentrantLock` 的同步控制核心。使用 AQS 状态来表示锁的保留数。
192-
* `Sync` 是一个抽象类,有两个子类:
193-
* `FairSync` - 公平锁版本。
194-
* `NonfairSync` - 非公平锁版本。
184+
ReentrantLock 的核心方法当然是 Lock 中的方法(具体实现完全基于 `Sync` 类中提供的方法)。
195185

196-
##### 重要属性
197-
198-
`Sync` 的实例。
186+
此外,ReentrantLock 有两个构造方法,功能参考下面源码片段中的注释。
199187

200188
```java
189+
// 同步机制完全依赖于此
201190
private final Sync sync;
202-
```
203-
204-
##### 重要方法
205-
206-
**构造方法**
207-
208-
```java
209-
// 默认初始化一个非公平的重入锁
191+
// 默认初始化 sync 的实例为非公平锁(NonfairSync)
210192
public ReentrantLock() {}
211-
// 根据 boolean 值选择初始化一个公平的或不公平的重入锁
193+
// 根据 boolean 值选择初始化 sync 的实例为公平的锁(FairSync)或不公平锁(NonfairSync)
212194
public ReentrantLock(boolean fair) {}
213195
```
214196

215-
**实现 Lock 接口的方法**
197+
#### Sync
216198

217-
以下方法的功能可以参考 [Lock](#lock-接口) 中的描述。具体实现完全基于 `Sync` 类中提供的方法。
199+
* `Sync` 类是 `ReentrantLock` 的内部类,也是一个抽象类。
200+
* `ReentrantLock` 的同步机制几乎完全依赖于`Sync`。使用 AQS 状态来表示锁的保留数(详细介绍参见 [AQS](#aqs))。
201+
* `Sync` 是一个抽象类,有两个子类:
202+
* `FairSync` - 公平锁版本。
203+
* `NonfairSync` - 非公平锁版本。
218204

219-
```java
220-
void lock();
221-
void lockInterruptibly() throws InterruptedException;
222-
boolean tryLock();
223-
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
224-
void unlock();
225-
Condition newCondition();
226-
```
205+
<p align="center">
206+
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/ReentrantLock-diagram.png">
207+
</p>
227208

228209
### 示例
229210

@@ -256,31 +237,29 @@ public class ReentrantLockDemo {
256237
}
257238
```
258239

240+
:point_right: [更多示例](https://github.com/dunwu/javase-notes/tree/master/codes/concurrent/src/main/java/io/github/dunwu/javase/concurrent/lock)
241+
259242
## ReadWriteLock 和 ReentrantReadWriteLock
260243

261244
### 要点
262245

263-
作用
264-
265246
对于特定的资源,ReadWriteLock 允许多个线程同时对其执行读操作,但是只允许一个线程对其执行写操作。
266247

267-
ReentrantReadWriteLock 实现了 ReadWriteLock 接口,所以它是一个读写锁
248+
ReadWriteLock 维护一对相关的锁。一个是读锁;一个是写锁。将读写锁分开,有利于提高并发效率
268249

269-
原理
250+
ReentrantReadWriteLock 实现了 ReadWriteLock 接口,所以它是一个读写锁。
270251

271252
“读-读”线程之间不存在互斥关系。
272253

273254
“读-写”线程、“写-写”线程之间存在互斥关系。
274255

275-
ReadWriteLock 维护一对相关的锁。一个是读锁;一个是写锁。将读写锁分开,有利于提高并发效率。
276-
277256
<p align="center">
278257
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/ReadWriteLock.jpg">
279258
</p>
280259

281260
### 源码
282261

283-
#### ReadWriteLock
262+
#### ReadWriteLock 接口定义
284263

285264
```java
286265
public interface ReadWriteLock {
@@ -298,7 +277,7 @@ public interface ReadWriteLock {
298277

299278
### 示例
300279

301-
```
280+
```java
302281
public class ReentrantReadWriteLockDemo {
303282

304283
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

0 commit comments

Comments
 (0)