ReentrantLock源码分析
先看 ReentrantLock 的类图
ReentrantLock 实现了 Lock 接口来完成加锁、释放锁等基本功能。
内部类Sync实现了 AQS 完成具体的锁独占、排队、释放等逻辑。 并提供了公平锁和非公平锁两种方式。
# 构造函数
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
1
2
3
4
5
6
2
3
4
5
6
无参构造函数默认使用非公平锁,也可通过有参构造函数指定使用公平锁。
# 公平锁与非公平锁
两者都是继承自内部类 Sync 。并且分别重写了 lock 和tryrelease 方法,这也就是两则的区别之处。
# 非公平锁
final void lock() {
//cas尝试获取锁 当前资源未被加锁情况下,有可能加锁成功
//加锁失败的情况 1.已被其他线程独占,2. 已被当前线程独占
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
public final void acquire(int arg) {
//再次尝试加锁失败则添加到等待队列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//未加锁状态 尝试获取锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 已被加锁 但独占线程是当前线程 , 则获取锁成功 ,记录加锁次数,用锁重入
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
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
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
非公平锁在加锁时,使用 cas 直接尝试抢占锁, 抢占失败,再将锁加入等待队列。
# 公平锁
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//此处即是与非公平锁不同之处
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
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
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
公平锁在抢占锁时,会先检查等待队列是否为空,或者当前线程位于等待队列队首,符合这一条件才能进行抢占。
编辑 (opens new window)
上次更新: 2023/04/09, 16:34:32