加锁流程
ReentrantLock.lock
java
public void lock() {
sync.lock();
}
sync 是 ReentrantLock 内部抽象类,继承自 AQS
ReentrantLock 构造方法
java
// 默认构造:非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
// 传 true = 公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
NonfairSync
lock
java
// AQS 变量,state = 0 表示空闲,> 0 表示被占用
private volatile int state;
final void lock() {
// CAS 操作更改状态
if (compareAndSetState(0, 1))
// 获取锁成功 修改拥有者线程
setExclusiveOwnerThread(Thread.currentThread());
else
// 获取锁失败
acquire(1);
}
acquire
线程抢锁成功,直接修改持有者线程,然后退出
如果抢锁失败,进入 acquire 方法
acquire 首先会再次尝试获取锁,依旧获取锁失败后,会创建一个 Node 节点并将 Node 加入等待队列中
java
public final void acquire(int arg) {
// 再次尝试获取锁
if (!tryAcquire(arg) &&
// addWaiter 将当前等待线程封装为 Node 放入队列中
// 获取锁失败加入等待队列
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// acquireQueued 返回 true 会进入到该分支,说明当前抢锁的线程已经被要求中断,所以这里要执行 selfInterrupt
selfInterrupt();
}
tryAcquire
尝试通过 CAS 获取锁,如果获取成功则返回 true,否则返回 false
java
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 非公平锁尝试获取锁
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取当前 state
// 分支1:锁空闲 state=0
if (c == 0) {
// 再次 CAS 抢锁
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 分支2:锁被占用,判断【是不是当前持有线程】= 可重入逻辑
else if (current == getExclusiveOwnerThread()) {
// 重入:state + 1
int nextc = c + acquires;
// 重入次数溢出校验(int 最大值保护)
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 分支3:锁被其他线程占用,获取锁失败
return false;
}
addWaiter
创建节点并加入等待队列
java
private Node addWaiter(Node mode) {
// mode = Node.EXCLUSIVE
// 把当前线程 + 独占模式 封装成 Node 节点
Node node = new Node(Thread.currentThread(), mode);
// 快速尝试:直接追加到队列尾(无锁入队)
Node pred = tail;
if (pred != null) {
node.prev = pred;
// CAS 尝试修改尾节点
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 快速入队失败(队列空 / 竞争失败),走完整入队逻辑
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
//第一次调用时,tail 为 null
Node t = tail;
if (t == null) { // Must initialize
//尝试设置head=new node
if (compareAndSetHead(new Node()))
//将tail设置为head, tail head都为new Node()
//再进入循环,t=new Node().进入else
tail = head;
} else {
//t=new node ,node为刚才ThreadB的node
node.prev = t;
//尝试把ThreadB的node赋值给tail
if (compareAndSetTail(t, node)) {
//赋值成功,headnode的后节点指向B的node,tail=B线程节点
t.next = node;
//返回head节点,跳出方法
return t;
}
}
}
acquireQueued
- 队列中只有头节点的下一个节点才有资格抢锁
- 一直自旋,直到将节点的状态修改完成后,再进入阻塞状态
- shouldParkAfterFailedAcquire:修改节点等待状态,决定是否调用 park()。
- parkAndCheckInterrupt():调用 Unsafe.park () 阻塞当前线程
java
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取 node 的前一个节点
final Node p = node.predecessor();
// 如果 p 是头节点 则代表 node 是第一个线程节点, 那就再尝试获取一次锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// shouldParkAfterFailedAcquire 修改节点等待状态,只有 shouldParkAfterFailedAcquire 返回 true 才会执行 parkAndCheckInterrupt
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // 等待线程被唤醒后从该方法开始执行
interrupted = true;
}
} finally {
// 如果抛出了异常(加锁不成功), failed 会为 true
if (failed)
// 将当前节点的状态设置为 canceled
// 对等待节点进行重新排序
// 唤醒后继节点
cancelAcquire(node);
}
}
//pred为ThreadB的Node的前节点,即head节点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// pred.waitStatus默认为0,进入else流程
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
//把node的waitStatus从0改成SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
释放锁
ReentrantLock.unlock
java
public void unlock() {
sync.release(1);
}
NonfairSync
release
java
public final boolean release(int arg) {
// 尝试释放锁
if (tryRelease(arg)) {
Node h = head;
// 队列有等待节点,唤醒后继线程
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// node 是 队列中的头节点
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
//ws为-1
int ws = node.waitStatus;
if (ws < 0)
//进入该逻辑,将head节点的waitStatus更改为0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//找到B线程的node节点
Node s = node.next;
//B线程的node节点不为空,waitStatus为-1不进入
if (s == null || s.waitStatus > 0) {
s = null;
//如果B节点失效,或者已经取消或者并发还没有赋值,从后往前找,找到第一个需要执行的 node,t==null或者t==当前head节点,才跳出
//为什么?enq方法里面,if没有锁 线程A通过CAS进入if语句块之后,发生上下文切换,此时线程B同样执行了该方法,并且执行完毕。然后线程C调用了unparkSuccessor方法。
// 假如是从头到尾的遍历形式,线程A的next指针此时还是null!也就是说,会出现后续节点被漏掉的情况。
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//得到我需要要unpark的线程,这里为ThreadB
if (s != null)
//解锁threadB
LockSupport.unpark(s.thread);
}
tryRelease
java
protected final boolean tryRelease(int releases) {
// state 减去释放次数
int c = getState() - releases;
// 校验:必须是持有锁的线程才能解锁
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 重入次数减到 0 → 锁完全释放
if (c == 0) {
free = true;
// 清空持有线程标记
setExclusiveOwnerThread(null);
}
// 更新 state
setState(c);
return free;
}
公平锁与非公平锁的区别
公平锁加了 hasQueuedPredecessors(),先判断队列是否有人排队,有人就乖乖排队,不插队
java
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;
}