首先,想先梳理一下自己看源碼的目的,最近有篇文章特別火《程序員12小時驚魂記:凌晨遷移數據出大事故!》,裏面強調了解決問題的能力很重要,這給我一種只看源碼和設計模式關鍵時刻不給力的感覺,週末去看了魯能和恆大的比賽,那種在瞬間做出決策的壓力只會比事故現場更緊張,而且不能有一點猶豫。我想競技體育的魅力,就在於此吧,要把所有的技能都訓練到潛意識層面,纔會在瞬間爆發出來。所以,要不斷的研究不斷的實踐,弄懂原理,融匯貫通。
看源碼步驟:
1、選中類名右擊,選中Giaggrams->Show Diagram查看類關係圖。
2、在類關係圖中右擊,選中Show Categories->Methods等查看類屬性和方法等。可以看到ReentrantLock實現了Lock,Serializable兩個接口,有Sync、NonfairSync和FairSync三個內部類,NonfairSync和FairSync繼承Sync類,Sync繼承和ReentrantLock同一個包下的AbstractQueuedSynchronizer抽象類。
3、在自己的測試工程中寫一個測試類,創建ReentrantLock對象,調用其中的方法。
public class ReentrantLockTest {
public static void main(String[] args){
ReentrantLock reentrantLock = new ReentrantLock();
reentrantLock.lock();
reentrantLock.unlock();
}
}
(1)從構造函數開始看,無參構造方法中只是實現了sync = new NonfairSync(),即默認使用非公平鎖。
(2)常用的方法lock(),實現很簡單,只是調用了sync.lock(),抽象方法,由子類實現。查看默認的非公平鎖的實現。
final void lock(){
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
} else{
acquire(1);
}
}
public final void acquire(int arg){
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE),arg)){
selfInterrupt();
}
}
- setExclusiveOwnerThread把當前線程設置成持有鎖的線程。
- 如果CAS失敗,說明鎖已經被別人獲取,那麼通過acquire()嘗試去獲取鎖。
- 其中的抽象類的非抽象方法,AbstractQueuedSynchronizer.java中tryAcquire方法,在抽象類中只是簡單了拋出了異常,這種主要是由子類去實現,要去看不同的子類都是怎麼實現的該方法。這個方法中,由FairSync公平鎖和NonFairSync非公平鎖的來實現此方法。
- 在NonFairSync非公平鎖中調用nonfairTryAcquire(acquires);
final boolean nonfairTryAcquire(int acquires){
final Thread current = Thread.currentThread();
int c = getStatus();
if (c == 0){
if (compareAndSetState(0,1)){
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;
}
- getStatus()獲取的狀態,就是上面CAS設置的狀態,如果狀態(c ==
0)說明當前沒有任何線程獲取到鎖,那就再獲取一遍鎖,設置線程,返回true; - current == getExclusiveOwnerThread()說明當前線程重入。
- setState(),把重入次數+1更新到status,返回true說明獲取到這個鎖。
- 繼續看acquire()方法中的判斷條件,addWaiter(Node.EXCLUSIVE)中 EXCLUSIVE定義 = null; 註釋中表明,此標記表示節點在獨佔模式下等待。
private Node addWaiter(Node mode){
Node node = new Node(Thread.currentThread(),mode);
Node pred = tail;
if (pred != null){
node.prev = pred;
if (compareAndSetTail(pred,node)){
pred.next = node;
return node;
}
}
enq(node);
return node;
}
private Node enq(final Node node){
for (;;){ // me:原來必須初始化是這樣寫
Node t = tail;
if (t == null){ //Must initialize
if (compareAndSetHead(new Node())){
tail = head;
}
} else {
node.prev = t;
if (compareAndSetTail(t,node)){
t.next = node;
return t;
}
}
}
}
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
static final class Node{
...
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
Node(Thread thread, Node mode){
this.nextWaiter = mode;
this.thread = thread;
}
...
}
}
- pred != null,說明當前鏈表不爲空,則把node追加到鏈表的尾部,並返回node。
- addWaiter()方法保證把Node放到一個鏈表裏去,並返回尾節點。
- 繼續看acquire()方法中的判斷條件,acquireQueued(addWaiter(Node.EXCLUSIVE),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;
}
if (shouldParkAfterFailedAcquire(p,node) &&
parkAndCheckInterrupt()){
interrupted = true;
}
}
} finally {
if (failed)
cancleAcquire(node);
}
}
- p == head是鏈表的特性,head節點不存數據,所以如果當前節點的前驅節點爲head時,則移除掉原head,把當前node節點設置爲head。
- shouldParkAfterFailedAcquire()裏面有信號量,第一次執行結果爲false,且設置信號量,繼續執行for的死循環,使用信號量,將線程掛起,然後等待一直線程被喚起。
- finally表示如果執行過程中有異常情況,則取消當前線程獲取鎖的動作。
- for循環,從傳入的尾節點開始,不斷的獲取前驅節點,只有在獲取到head節點時,才能走到唯一的出口
- 繼續看acquire(),如果獲取鎖失敗,且發生線程中斷,則中斷當前線程。