ReentrantLock源码笔记

好奇ReentrantLock源码, 就看了下,顺便做个笔记,
ReentrantLock有两种锁,一种是公平锁fairSync,另一个是非公平锁NonfairSync,默认情况下是非公平锁。

然后看lock上锁方法发现调用的是AQS的acquire方法
lock
if判断利用的短路特性,tryAcquire(int)是真正的抢锁方法,如果抢锁成功,直接结束判断,如果抢锁失败,进行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)处理,
addWaiter(Node.EXCLUSIVE)将当前线程以独占模式挂到等待队列,
等待队列是个双向链表,链表头节点不存储线程

tryAcquire(int)在AQS里只抛出了UnsupportedOperationException,看实现,ReentrantLock的NonfairSync和FairSync实现了tryAcquire(int),NonfairSync真正调用的是nonfairTryAcquire(int)方法

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
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取当前锁的状态,state=0代表无线程获取锁,>0代表锁已经被获取
int c = getState();
//state==0,无线程占用锁
if (c == 0) {
//0,尝试获取锁CAS,原子操作
if (compareAndSetState(0, acquires)) {
//获取成功,当前线程独占该锁
setExclusiveOwnerThread(current);
//返回true
return true;
}
}
//如果不等于0,锁已经被占用,判断占用锁的线程是否是当前线程
else if (current == getExclusiveOwnerThread()) {
//是,state值+1,表示该锁被重入,返回true,(可重入原理)
int nextc = c + acquires;
// 溢出
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//state+1
setState(nextc);
return true;
}
//否,返回false,获取锁失败
return false;
}

acquireQueued,shouldParkAfterFailedAcquire方法

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
 final boolean acquireQueued(final Node node, int arg) {
//线程中断位
boolean interrupted = false;
try {
for (;;) {
//获取当前线程节点的前一节点,
final Node p = node.predecessor();
//如果是头结点,就尝试拿锁(应该是为了之后的唤醒准备的)
if (p == head && tryAcquire(arg)) {
//设置头结点为当前线程的节点,之前的头结点就扔掉了,
//并且node的线程和前置节点被清空,
setHead(node);
p.next = null; // help GC
// 返回中断状态
return interrupted;
}
//是否挂起线程,
if (shouldParkAfterFailedAcquire(p, node))
//进行线程挂起,且线程被唤醒之后检查中断状态(parkAndCheckInterrupt方法内)
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
// 出现异常,节点状态改为CANCEL,从队列删除节点,将后继节点唤醒或者挂到前一节点上
cancelAcquire(node);
// 清除中断状态
if (interrupted)
selfInterrupt();
throw t;
}
}


/*
* 线程节点的四种状态,CANCEL(1),SIGNAL(-1),CONDITION(-2),PROPAGATE(-3)
* CANCEL: 取消状态,该状态的节点需要从等待队列删除,并且不会变为其他状态,
* SIGNAL: 表示当前节点释放锁时需要唤醒后继节点
* CONDITION: 该状态的节点处于条件队列,并且处于该状态的线程不会导致state+1,用于Lock-Condition机制
* PROPAGATE: 该状态的线程可以被唤醒,用于共享锁
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//如果等待队列当前节点的前置节点线程是SIGNAL状态,则当前线程是可以被挂起的
return true;
if (ws > 0) {
//如果前置节点是CANCEL状态,循环,找到第一个不是CANCEL状态的节点,挂在后面,然后再抢一次锁
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//如果前置节点不是CANCEL状态,把前置节点设为SIGNAL状态(不一定成功),再次尝试获取锁
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}

其中