相关方法流程
1. ReentrantLock.lock
public void lock() {
sync.lock();
}
ReentrantLock.lock
会调用sync.lock
,当锁为非公平锁时,sync
的类型为ReentrantLock.NonfairSync
。
2. NonfairSync.lock
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
这里首先会尝试使用CAS将状态从0改变到1(在这里,状态0表示当前没有线程持有这个锁);如果成功,则表示获取锁成功,将占有锁线程设置为当前线程;如果失败,则调用acquire(1)
方法。
3. AQS.acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// NonfairSync
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
// 在先不考虑线程重入的情况下,这个方法就是使用CAS将当前状态值从0修改为1。如果成功,那么当前线程抢占锁。
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;
}
首先尝试使用tryAcquire
获取锁。由于刚才已经获取失败,所以这里会返回false。重点看acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
这里。
4. AQS.acquireQueued
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) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
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;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
addWaiter
很简单,就是将当前线程加入到等待队列中。
而acquireQueued
则是调用tryAcquire
方法。如果获取失败,则阻塞(park)直到下一次被唤醒,依此无限循环。
总结
ReentrantLock类中持有一变量sync
,即同步器,这是一个继承自AQS的Sync
类型的变量。在类型为非同步锁的情况下,这个对象的真实类型为NonfairSync
。
sync
对象保存了当前同步器的状态(0为无线程持有锁),以及当前持有锁的线程。
- 在调用
ReentrantLock.lock
后,首先会尝试将sync
的状态从0改为1。 - 如果成功,则设置持有线程为当前线程并返回,加锁成功。
如果失败,则再次尝试修改状态(如果state为0则尝试修改为1,如果state不为0且持有线程为当前线程,则state++);若再次失败,则将当前线程加入等待队列。加入等待队列之后,会再尝试获取锁,如果失败,则挂起(park)该线程。 - 在锁被释放时,会唤醒等待队列中的第一个线程,使其尝试竞争锁(和处于前2步的线程竞争)。如果失败,则再将其挂起直到下一次被唤醒。