这里是目录呀
只分析代码,意在整理一次思路
有些方法源码不在一起,为了方便分析,我放在一起并做了简单说明
创建使用
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
ReentrantLock 构造
//
public ReentrantLock() {
sync = new NonfairSync();
}
lock时
public void lock() {
sync.lock();
}
sync.lock() 是 NonfairSync 实现的所以看
final void lock() {
// CAS原子设置state,如果设置成功返回true
if (compareAndSetState(0, 1))
// 设置持有锁的线程
setExclusiveOwnerThread(Thread.currentThread());
else
// 设置失败,说明state == 1,有线程在持有状态,这时执行 acquire(1);
acquire(1);
}
acquire 走的是父类 AbstractQueuedSynchronizer
public final void acquire(int arg) {
// 这里有 tryAcquire acquireQueued addWaiter
// 只有 tryAcquire(1) 返回 false
// 并且 acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 返回true
// 才会执行 selfInterrupt()
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
接着 分析 tryAcquire(1) 由子类实现,查看子类 NonfairSync
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 调用了 NonfairSync 的父类 Sync 实现
final boolean nonfairTryAcquire(int acquires) {
// 获取当前线程
final Thread current = Thread.currentThread();
// 获取状态
int c = getState();
if (c == 0) {
// 如状态 == 0,尝试获取锁
if (compareAndSetState(0, acquires)) {
// 获取成功,设置当前线程持有锁
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
// 如果是当前线程再次调用,则状态加acquires,就是 + 1
int nextc = c + acquires;
// 边界校验
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 设置状态,或者到这可以理解state是计数器,记录当前线程调用过几次lock
// 这段可以说是可重入锁的核心实现了
setState(nextc);
return true;
}
return false;
}
这段代码可以看出,tryAcquire 先判断是否为锁状态
当state 非0时表示有线程在持有,如果是当前线程,会把state++
也就是说(state != 0 && current != getExclusiveOwnerThread())
返回false,当 tryAcquire 返回 false 时
我们接着看 addWaiter
private Node addWaiter(Node mode) {
// 创建当前线程节点
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
// 如果尾部不为空,当前的上级设置成尾部
// 题外话,第一次 pred = tail = head,这里是把当前节点的上一个指向头节点
// 之后,perd = tail,这里是把 当前节点的上一个替换成原先的尾部节点
node.prev = pred;
if (compareAndSetTail(pred, node)) {
// 原子操作,把尾部设置为当前节点
// 原先的尾部节点设置为当前节点
// 至此形成一个链
pred.next = node;
return node;
}
}
// 如果 尾部节点没初始化,第一次会进入 enq 进行初始化 tail = head
// 然后 执行更上边一样的逻辑将节点放到链表内
enq(node);
return node;
}
再看 acquireQueued(final Node node, int arg)
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
// 如果上一个节点是头节点,开始获取锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;// 未失败
return interrupted;// 返回是否中断
}
// 检查是否阻塞shouldParkAfterFailedAcquire
// 通过 parkAndCheckInterrupt 进行阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
又发现 3个方法,别慌,挨个看
shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 5种状态 0、PROPAGA(-3)、CONDITION(-2)、SIGNL(-1)|下次自旋阻塞 CANCELLE(1)|线程已取消
// 如果waitStatus = -1 允许阻塞
// 如果 waitStatus > 0
if (ws == Node.SIGNAL)
// 如果是SIGNAL(-1) 进行阻塞
return true;
if (ws > 0) {
// 循环检测向上检测,把CANCELLE(1)都从链表清除
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 设置pred 为 SIGNAL(-1) 下次自旋可以进入阻塞
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);// Emmm 阻塞this 没啥好说的
// 我还是忍不住想说,在什么时候会解除阻塞
// 1、有人调用unpark 2、线程interrupt 3、任性返回
return Thread.interrupted();// 返回线程的中断状态
}
执行完后如果 是失败的会执行 cancelAcquire
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// 整理向上链表,跳过 CANCELLE(1)
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
Node predNext = pred.next;
node.waitStatus = Node.CANCELLED;
// 如果是尾部,移除自己
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
// 下一个节点需要信号,那就设置信号,然后移除当前节点
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
// 唤醒下一个未取消的节点线程
unparkSuccessor(node);
}
// 节点的下一个指向自己
// 这里没有处理prev是因为shouldParkAfterFailedAcquire方法处理了
// 这里处理prev不安全,因为这里已经获取到锁了
node.next = node; // help GC
}
}
此时 acquireQueued 就已经执行完了,小记
shouldParkAfterFailedAcquire 执行时 只处理 CANCELLE(1) 状态的 prev
获取状态失败时 cancelAcquire 会处理 next关系
Node的 5种状态:
- 0 正常运行
- PROPAGA(-3) 阻塞
- CONDITION(-2) 阻塞
- SIGNL(-1) 阻塞
- CANCELLE(1) 已取消或已中断
unlock时
public void unlock() {
sync.release(1);
}
AQS的 release
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
// 如果头节点是1、-1、-2、-3等状态
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
子类Sync 实现 tryRelease(1)
protected final boolean tryRelease(int releases) {
// 状态 - 1
int c = getState() - releases;
// 如果不是当前线程,抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 如果计数清零了
if (c == 0) {
free = true;
// 设置当前线程为null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
接着看 unparkSuccessor
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
// 如果还在等待状态 ,重置为0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// 如果 下个节点是 CANCELLE(1) 状态
if (s == null || s.waitStatus > 0) {
s = null;
// 从尾部开始查找,查找到第一个 非 CANCELLE(1) 状态的节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
// 如果节点不为空,唤醒节点代表的线程
LockSupport.unpark(s.thread);
}
此时下一个等待唤醒的线程会被唤醒 acquireQueued 方法的自旋中 去获取锁,acquireQueued 方法执行完如果线程中断,会走 acquire 方法的 selfInterrupt()
来看看 selfInterrupt 执行了什么
static void selfInterrupt() {
// 线程中断信号
Thread.currentThread().interrupt();
}
简单用法应该是分析完了,欢迎探讨,如有缺漏,望指正。