Franz`s blog

ReentrantLock源码分析

因为在学习ReentrantLock源码的过程中发现网上相关文章的源码都比较老了,所以写了这篇文章。
本文中提到的源码均为jdk17中的源码
我们先看ReentrantLock中常用的几个关键的方法

1
2
3
public void lock() {
sync.lock();
}
1
2
3
public void unlock() {
sync.release(1);
}

都是通过ReentrantLock内部的sync实现的,而Sync是ReentrantLock是中实现了AbstractQueuedSynchronizer的一个内部类,Sync的主要子类有NonfairSyncFairSync
具体关系如下
image.png

我们先看Sync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
abstract static class Sync extends AbstractQueuedSynchronizer {
/**
* 执行非公平 tryLock。
*/
@ReservedStackAccess
final boolean tryLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
}
return false;
}

/**
* Checks for reentrancy and acquires if lock immediately
* available under fair vs nonfair rules. Locking methods
* perform initialTryLock check before relaying to
* corresponding AQS acquire methods.
*/
/**
* 具体实现交到子类 NonfairSync 和 FairSync
* 模板方法设计模式
*
*/
abstract boolean initialTryLock();

@ReservedStackAccess
final void lock() {
// 如果通过cas获取锁失败通过acquire将线程放入等待队列
if (!initialTryLock())
// acquire 是 aqs调用子类中的 tryAcquire() 模板方法的一种体现
/**
AQS中的相关代码

public final void acquire(int arg) {
// 尝试获取资源
if (!tryAcquire(arg))
// 获取失败加入等待队列
acquire(null, arg, false, false, false, 0L);
}

*/
acquire(1);
}

// 独占式释放锁
/*
ReentranLock通过unlock 调用
public void unlock() {
sync.release(1);
}
*/

@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases; // 重入次数减少
// 独占的线程不是当前线程
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
// 重入次数减少到 0
boolean free = (c == 0);
if (free)
setExclusiveOwnerThread(null);
setState(c);
return free;
}

// 是否当前线程独占
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}

}

我们主要关注的就是locktryRelease方法

NonfairSyncFairSync中是否公平的也是通过实现initialTryLocktryAcquire实现的
NonfairSync的源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static final class NonfairSync extends Sync {

final boolean initialTryLock() {
Thread current = Thread.currentThread();
// cas 尝试改变 state 状态
if (compareAndSetState(0, 1)) { // first attempt is unguarded
setExclusiveOwnerThread(current);
return true;
} else if (getExclusiveOwnerThread() == current) {
// 可重入
int c = getState() + 1;
if (c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
} else
return false;
}

/**
* Acquire for non-reentrant cases after initialTryLock prescreen
*/
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}


发现我们上文提到的initialTryLocktryAcquire最终都在这里实现了。
NonfairSyncFairSync区别其实就是在将自己设为独占线程之前判断等待队列中是否存在在自己之前的线程在等待该资源。

1
2
3
4
5
6
7
8
 //NonfairSync 设置独占线程之前的判断,不会去判断是否存在别的线程在等待  
if (compareAndSetState(0, 1))
// FairSync 设置独占线程之前的判断,会去判断是否存在别的线程在等待
if (!hasQueuedThreads() && compareAndSetState(0, 1))
// NonfairSync
if (getState() == 0 && compareAndSetState(0, acquires))
// FairSync
if (getState() == 0 && !hasQueuedPredecessors() && compareAndSetState(0, acquires))

最终调用流程