ReentrantLock 的 lock 办法源码
ReentrantLock
中的 lock
办法,首要调用内部类 Sync
中的笼统 lock
办法。该办法首要有两套完成,一套是公正锁,一套对错公正锁。
公正锁
final void lock() {
acquire(1);
}
公正锁中,直接调用 acquire
办法。
非公正锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
非公正锁中,首要测验将 AQS
中的 state
属性从 0
变成 1
,假如成功,则代表获取锁资源成功;否则调用 acquire
办法。
ReentrantLock 的 acquire 办法源码
acquire
办法中没有实践的事务处理,都是在调用其他办法。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- 首要调用
tryAcquire
办法,测验获取锁资源,假如获取成功,则回来true
,办法结束。假如获取失利,则调用&&
后面的办法。 - 调用
addWaiter()
办法,将线程封装到Node
节点并添加到行列尾部。 - 之后再调用
acquireQueued()
办法检查当时排队的Node
是否在行列的前面,假如在前面,测验获取锁资源。假如没在前面,线程进入到阻塞状况。
ReentrantLock 的 tryAcquire 办法源码
tryAcquire()
办法分公正锁和非公正锁两套完成,首要做了两件事:
- 假如
AQS
当时state
为0
,测验获取锁资源。 - 假如
AQS
当时state
不为0
,检查是否是可重入操作。
公正锁
protected final boolean tryAcquire(int acquires) {
// 获取当时线程
final Thread current = Thread.currentThread();
// 获取AQS当时state值
int c = getState();
// 判断state是否为0,为0则代表当时没有线程持有锁
if (c == 0) {
// 首要判断是否有线程在排队,假如有,tryAcquie()办法直接回来false
// 假如没有,则测验获取锁资源
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 假如state != 0,则代表有线程持有锁资源
// 判断占有锁的线程是不是当时线程,假如是,则进行可重入操作
else if (current == getExclusiveOwnerThread()) {
// 可重入
int nextc = c + acquires;
// 检查锁重入是否超越最大值,二进制第一位表明符号
// 01111111 11111111 11111111 11111111
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
非公正锁
final boolean nonfairTryAcquire(int acquires) {
// 获取当时线程
final Thread current = Thread.currentThread();
// 获取AQS当时state值
int c = getState();
// 假如state == 0,说明没有线程占用着当时的锁资源
if (c == 0) {
// CAS直接测验获取锁资源,直接抢锁,不论有没有线程在行列中
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
// 检查锁重入是否超越最大值,二进制第一位表明符号
// 01111111 11111111 11111111 11111111
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 修改state当时值
setState(nextc);
return true;
}
return false;
}
ReentrantLock 的 addWaiter 办法源码
private Node addWaiter(Node mode) {
// 将当时线程封装为Node对象,mode为null,代表互斥锁
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
// pred指向tail
Node pred = tail;
if (pred != null) {
// 当时线程Node节点的prev指向pred节点
node.prev = pred;
// 以CAS办法,测验将node节点变成tail
if (compareAndSetTail(pred, node)) {
// 将pred的next指向node
pred.next = node;
return node;
}
}
// 假如上述办法,CAS操作失利,导致加入到AQS结尾失利,就根据enq的办法添加到AQS行列
enq(node);
return node;
}
在 tryAcquire()
办法获取锁资源失利之后,首要创建当时线程的 Node
节点,之后将该节点添加到行列尾部。
private Node enq(final Node node) {
// 死循环,直到刺进成功
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//假如尾节点为null,说明同步行列还未初始化,则CAS操作新建头节点
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 将node的prev指向当时的tail节点
node.prev = t;
// CAS测验将node变成tail节点
if (compareAndSetTail(t, node)) {
// 将之前尾节点的next指向要刺进的节点
t.next = node;
return t;
}
}
}
}
ReentrantLock 的 acquirdQueued 办法源码
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取node的前一个节点
final Node p = node.predecessor();
// 假如前一个节点为head并测验获取锁资源
if (p == head && tryAcquire(arg)) {
// 测验获取锁资源成功,将node节点设置为头节点,thread和prev属性置位null
setHead(node);
// 将之前的头节点的next指向null,帮助快速GC
p.next = null; // help GC
failed = false;
return interrupted;
}
// 假如前一个节点不是head或者获取锁资源失利
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// 保证上一个节点的状况是正确的
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
if (ws > 0) {
// 循环往前找,找到一个状况小于等于0的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 假如不是-1,可是小于等于0,将状况修改为-1
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
acquireQueued
办法会检查当时排队的 Node
的前一个节点是不是 head
,假如是,测验获取锁资源。假如不是或者获取锁资源失利,那么就测验将当时 Node
的线程挂起。
在挂起线程前,需求确认当时节点的上一个节点的状况是小于等于 0
:
假如为 1
,代表是取消的节点,不能挂起
假如为 -1
,代表挂起当时线程
假如为 -2
,-3
,需求将状况改为 -1
之后,才干挂起当时线程
ReentrantLock 的 unlock 办法源码
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
// 中心开释锁办法
if (tryRelease(arg)) {
Node h = head;
// 假如头节点不为null,并且头节点的状况不为0,唤醒排队的线程
if (h != null && h.waitStatus != 0)
// 唤醒线程
unparkSuccessor(h);
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
// 获取头节点状况
int ws = node.waitStatus;
// 假如头节点状况小于0,换为0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 拿到当时节点的next
Node s = node.next;
// 假如s == null ,或者s的状况为1
if (s == null || s.waitStatus > 0) {
// next节点不需求唤醒,需求唤醒next的next
s = null;
// 从尾部往前找,找到状况正常的节点。(小于等于0代表正常状况)
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 通过循环的获取,假如拿到状况正常的节点,并且不为null
if (s != null)
// 线程唤醒
LockSupport.unpark(s.thread);
}
// 中心的开释锁资源办法
protected final boolean tryRelease(int releases) {
// state - 1
int c = getState() - releases;
// 假如开释锁的线程不是占用锁的线程,抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// 是否成功的将锁资源开释
boolean free = false;
if (c == 0) {
// 假如state = 0,代表成功开释锁资源
free = true;
setExclusiveOwnerThread(null);
}
// 设置state值
setState(c);
return free;
}