Skip to content

Commit 101f6d6

Browse files
committed
📝 Writing docs.
1 parent 0fa56a4 commit 101f6d6

1 file changed

Lines changed: 250 additions & 0 deletions

File tree

docs/concurrent/Java锁.md

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
---
2+
title: Java 锁
3+
date: 2018/05/16
4+
categories:
5+
- javase
6+
tags:
7+
- javase
8+
- concurrent
9+
- juc
10+
---
11+
12+
# Java 锁
13+
14+
> 本文内容基于 JDK1.8。
15+
16+
<!-- TOC depthFrom:2 depthTo:3 -->
17+
18+
- [概述](#概述)
19+
- [为什么会出现 Lock?](#为什么会出现-lock)
20+
- [synchronized](#synchronized)
21+
- [Lock 接口](#lock-接口)
22+
- [要点](#要点)
23+
- [源码](#源码)
24+
- [ReentrantLock](#reentrantlock)
25+
- [要点](#要点-1)
26+
- [源码](#源码-1)
27+
- [示例](#示例)
28+
- [ReadWriteLock](#readwritelock)
29+
- [要点](#要点-2)
30+
- [源码](#源码-2)
31+
- [ReentrantReadWriteLock](#reentrantreadwritelock)
32+
- [要点](#要点-3)
33+
- [示例](#示例-1)
34+
- [资料](#资料)
35+
36+
<!-- /TOC -->
37+
38+
## 概述
39+
40+
### 为什么会出现 Lock?
41+
42+
### synchronized
43+
44+
synchronized 是 Java 的内置锁。
45+
46+
如果一个代码块被 synchronized 修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
47+
48+
1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
49+
2. 线程执行发生异常,此时 JVM 会让线程自动释放锁。
50+
51+
如果这个获取锁的线程被阻塞了,但是又没有释放锁,其他线程就只能一直等待。
52+
53+
使用 synchronized,如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。
54+
55+
可重入锁可中断锁公平锁读写锁
56+
57+
## Lock 接口
58+
59+
### 要点
60+
61+
### 源码
62+
63+
Lock 接口
64+
65+
```java
66+
public interface Lock {
67+
/** 获取锁,如果锁已被其他线程获取,则进行等待。 */
68+
void lock();
69+
/**
70+
* 获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。
71+
* 当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,
72+
* 而线程B只有在等待,那么对线程B调用threadB.interrupt()* 方法能够中断线程B的等待过程。
73+
*/
74+
void lockInterruptibly() throws InterruptedException;
75+
/**
76+
* tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回 true。
77+
* 如果获取失败(即锁已被其他线程获取),则返回 false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
78+
*/
79+
boolean tryLock();
80+
/**
81+
* 这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
82+
* 如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
83+
*/
84+
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
85+
/** 释放锁 */
86+
void unlock();
87+
/**
88+
* 返回绑定到此Lock实例的新的Condition实例。
89+
* 在等待条件之前,锁必须由当前线程保持。对 Condition.await 的调用将在等待之前以原子方式释放锁,
90+
* 并在等待返回之前重新获取锁。
91+
*/
92+
Condition newCondition();
93+
}
94+
```
95+
96+
## ReentrantLock
97+
98+
### 要点
99+
100+
作用:字面意为可重入锁。原理
101+
102+
### 源码
103+
104+
ReentrantLock 实现了 Lock 接口,所以支持 Lock 的所有方法。
105+
106+
#### 内部类
107+
108+
* `Sync` 这个类是 `ReentrantLock` 的同步控制核心。使用 AQS 状态来表示锁的保留数。
109+
* `Sync` 是一个抽象类,有两个子类:
110+
* `FairSync` - 公平锁版本。
111+
* `NonfairSync` - 非公平锁版本。
112+
113+
#### 重要属性
114+
115+
`Sync` 的实例。
116+
117+
```java
118+
private final Sync sync;
119+
```
120+
121+
#### 重要方法
122+
123+
**构造方法**
124+
125+
```java
126+
// 默认初始化一个非公平的重入锁
127+
public ReentrantLock() {}
128+
// 根据 boolean 值选择初始化一个公平的或不公平的重入锁
129+
public ReentrantLock(boolean fair) {}
130+
```
131+
132+
**实现 Lock 接口的方法**
133+
134+
以下方法的功能可以参考 [Lock](#lock-接口) 中的描述。具体实现完全基于 `Sync` 类中提供的方法。
135+
136+
```java
137+
void lock();
138+
void lockInterruptibly() throws InterruptedException;
139+
boolean tryLock();
140+
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
141+
void unlock();
142+
Condition newCondition();
143+
```
144+
145+
### 示例
146+
147+
```java
148+
public class ReentrantLockDemo {
149+
150+
private ArrayList<Integer> arrayList = new ArrayList<Integer>();
151+
private Lock lock = new ReentrantLock();
152+
153+
public static void main(String[] args) {
154+
final ReentrantLockDemo demo = new ReentrantLockDemo();
155+
new Thread(() -> demo.insert(Thread.currentThread())).start();
156+
new Thread(() -> demo.insert(Thread.currentThread())).start();
157+
}
158+
159+
private void insert(Thread thread) {
160+
lock.lock();
161+
try {
162+
System.out.println(thread.getName() + "得到了锁");
163+
for (int i = 0; i < 5; i++) {
164+
arrayList.add(i);
165+
}
166+
} catch (Exception e) {
167+
e.printStackTrace();
168+
} finally {
169+
System.out.println(thread.getName() + "释放了锁");
170+
lock.unlock();
171+
}
172+
}
173+
}
174+
```
175+
176+
## ReadWriteLock
177+
178+
### 要点
179+
180+
* 功能
181+
* 对于特定的资源,ReadWriteLock 允许多个线程同时对其执行读操作,但是只允许一个线程对其执行写操作。
182+
* 原理
183+
* “读-读”线程之间不存在互斥关系。
184+
* “读-写”线程、“写-写”线程之间存在互斥关系。
185+
* ReadWriteLock 维护一对相关的锁。一个是读锁;一个是写锁。
186+
* 将读写锁分开,有利于提高并发效率。
187+
188+
<p align="center">
189+
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/ReadWriteLock.jpg">
190+
</p>
191+
192+
### 源码
193+
194+
ReadWriteLock 接口
195+
196+
```java
197+
public interface ReadWriteLock {
198+
/**
199+
* 返回用于读操作的锁
200+
*/
201+
Lock readLock();
202+
203+
/**
204+
* 返回用于写操作的锁
205+
*/
206+
Lock writeLock();
207+
}
208+
```
209+
210+
## ReentrantReadWriteLock
211+
212+
### 要点
213+
214+
* 功能
215+
* ReentrantReadWriteLock 实现了 ReadWriteLock 接口,所以它是一个读写锁。
216+
217+
### 示例
218+
219+
```
220+
public class ReentrantReadWriteLockDemo {
221+
222+
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
223+
224+
public static void main(String[] args) {
225+
final ReentrantReadWriteLockDemo demo = new ReentrantReadWriteLockDemo();
226+
new Thread(() -> demo.get(Thread.currentThread())).start();
227+
new Thread(() -> demo.get(Thread.currentThread())).start();
228+
}
229+
230+
public synchronized void get(Thread thread) {
231+
rwl.readLock().lock();
232+
try {
233+
long start = System.currentTimeMillis();
234+
235+
while (System.currentTimeMillis() - start <= 1) {
236+
System.out.println(thread.getName() + "正在进行读操作");
237+
}
238+
System.out.println(thread.getName() + "读操作完毕");
239+
} finally {
240+
rwl.readLock().unlock();
241+
}
242+
}
243+
}
244+
```
245+
246+
## 资料
247+
248+
* [Java 并发编程实战](https://item.jd.com/10922250.html)
249+
* [Java 并发编程的艺术](https://item.jd.com/11740734.html)
250+
* http://www.cnblogs.com/dolphin0520/p/3923167.html

0 commit comments

Comments
 (0)