相關(guān)方法流程
1. ReentrantLock.lock
public void lock() {
sync.lock();
}
ReentrantLock.lock
會(huì)調(diào)用sync.lock
宾濒,當(dāng)鎖為非公平鎖時(shí),sync
的類型為ReentrantLock.NonfairSync
。
2. NonfairSync.lock
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
這里首先會(huì)嘗試使用CAS將狀態(tài)從0改變到1(在這里鸿捧,狀態(tài)0表示當(dāng)前沒有線程持有這個(gè)鎖)泻轰;如果成功,則表示獲取鎖成功俗孝,將占有鎖線程設(shè)置為當(dāng)前線程酒甸;如果失敗,則調(diào)用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);
}
// 在先不考慮線程重入的情況下插勤,這個(gè)方法就是使用CAS將當(dāng)前狀態(tài)值從0修改為1。如果成功革骨,那么當(dāng)前線程搶占鎖农尖。
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
獲取鎖。由于剛才已經(jīng)獲取失敗良哲,所以這里會(huì)返回false盛卡。重點(diǎn)看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
很簡單筑凫,就是將當(dāng)前線程加入到等待隊(duì)列中滑沧。
而acquireQueued
則是調(diào)用tryAcquire
方法。如果獲取失敗巍实,則阻塞(park)直到下一次被喚醒滓技,依此無限循環(huán)。
總結(jié)
ReentrantLock類中持有一變量sync
蔫浆,即同步器殖属,這是一個(gè)繼承自AQS的Sync
類型的變量。在類型為非同步鎖的情況下瓦盛,這個(gè)對象的真實(shí)類型為NonfairSync
洗显。
sync
對象保存了當(dāng)前同步器的狀態(tài)(0為無線程持有鎖),以及當(dāng)前持有鎖的線程原环。
- 在調(diào)用
ReentrantLock.lock
后挠唆,首先會(huì)嘗試將sync
的狀態(tài)從0改為1。 - 如果成功嘱吗,則設(shè)置持有線程為當(dāng)前線程并返回玄组,加鎖成功滔驾。
如果失敗,則再次嘗試修改狀態(tài)(如果state為0則嘗試修改為1俄讹,如果state不為0且持有線程為當(dāng)前線程哆致,則state++);若再次失敗患膛,則將當(dāng)前線程加入等待隊(duì)列摊阀。加入等待隊(duì)列之后,會(huì)再嘗試獲取鎖踪蹬,如果失敗胞此,則掛起(park)該線程。 - 在鎖被釋放時(shí)跃捣,會(huì)喚醒等待隊(duì)列中的第一個(gè)線程漱牵,使其嘗試競爭鎖(和處于前2步的線程競爭)。如果失敗疚漆,則再將其掛起直到下一次被喚醒酣胀。