AQS是JUC框架中重要的類,經過它來實現獨佔鎖和共享鎖的,內部不少類都是經過AQS來實現的,好比CountDownLatch、ReentrantLock、ReentrantReadWriteLock、Semaphore。本章是對AbstractQueuedSynchronizer源碼進行分析。從獨佔鎖的獲取、釋放,共享鎖的獲取、釋放,以及Condition的await、signal三方面對源碼進行分析。先知道AQS的這幾點注意事項一、Condition條件變量只支持在獨佔鎖狀態下二、AQS支持同步隊列和條件隊列(條件隊列的數目根據Condition實例的數目),只有同步隊列中的節點線程才能獲取鎖三、AQS是個抽象類,提供獨佔鎖和共享鎖的公有方法,子類須要實現的幾個模板方法,①tryAcquire②tryRelease③tryAcquireShared④tryReleaseShared⑤isHeldExclusively。這幾點在下面代碼解析會分析到。還有一個AbstractQueuedLongSynchronizer類,它與AQS功能和實現幾乎同樣,惟一不一樣的是AQLS中表明鎖被獲取次數的屬性state類型是long類型,而AQS中該成員變量是int類型。AQS源碼對應的jdk版本是1.8。java
//此類只提供保存和獲取獨佔鎖線程,子類可使用適當的保留值來幫助控制和監控訪問並提供診斷
public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
private static final long serialVersionUID = 3737899427754241961L;
protected AbstractOwnableSynchronizer() { }
//獨佔鎖擁有者線程
private transient Thread exclusiveOwnerThread;
//設置獨佔鎖的擁有者線程,訪問權限protected,同包或者子類使用
protected final void setExclusiveOwnerThread(Thread thread) {
//將傳入進來的線程賦值給獨佔鎖擁有者線程
exclusiveOwnerThread = thread;
}
//獲取獨自鎖的擁有者線程,訪問權限protected,只能在同包或者子類使用
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
}複製代碼
//同步隊列的頭節點
private transient volatile Node head;
//同步隊列的尾節點
private transient volatile Node tail;
//同步狀態
private volatile int state;
//若是超時時間小於此閾值,不阻塞線程,讓其自旋,在doAcquireNanos、doAcquireSharedNanos、awaitNanos、await(long time, TimeUnit unit)方法使用到
static final long spinForTimeoutThreshold = 1000L;
//獲取UnSafe使用,若是對UnSafe使用不清楚的,能夠看下我分享的UnSafe的使用
private static final Unsafe unsafe = Unsafe.getUnsafe();
//屬性state的相對偏移量,相對AbstractQueuedSynchronizer實例的起始內存位置的相對偏移量,定義成靜態的緣由是,屬性的相對實例的偏移量都是相等的
private static final long stateOffset;
//屬性head的相對偏移量
private static final long headOffset;
//屬性tail的相對偏移量
private static final long tailOffset;
//內部類Node實例的屬性waitStatus的相對偏移量
private static final long waitStatusOffset;
//內部類Node實例的屬性next的相對偏移量
private static final long nextOffset;
static {
try {
//使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性state的相對偏移量
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
//使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性head的相對偏移量
headOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
//使用UnSafe實例獲取AbstractQueuedSynchronizer類的屬性tail的相對偏移量
tailOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
//使用UnSafe實例獲取AbstractQueuedSynchronizer內部類Node的屬性waitStatus的相對偏移量
waitStatusOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
//使用UnSafe實例獲取AbstractQueuedSynchronizer內部類Node的屬性next的相對偏移量
nextOffset = unsafe.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (Exception ex) { throw new Error(ex); }
}複製代碼
//經過Node咱們能夠實現兩個隊列,一是經過prev和next屬性實現CLH隊列(線程同步隊列,雙向隊列),二是nextWaiter屬性實現Condition條件上的等待條件隊列(單向隊列),在Condition中會詳細介紹。
static final class Node {
//當前節點是獲取共享鎖的標記
static final Node SHARED = new Node();
//當前節點是獲取獨佔鎖的標記
static final Node EXCLUSIVE = null;
//屬性waitStatus的值,標誌節點對應的線程被取消
static final int CANCELLED = 1;
//屬性waitStatus的值,標誌當前節點的next節點的線程(即隊列中當前節點的下一個節點)須要被阻塞
static final int SIGNAL = -1;
//屬性waitStatus的值,標誌當前節點在Condition條件下等待阻塞,在Condition實例的await系列方法中使用,新建一個waitStatus的值爲CONDITION的節點Node,將其加入到Condition中的條件隊列中,在Condition實現類詳細介紹
static final int CONDITION = -2;
//屬性waitStatus的值,標誌着下一個acquireShared方法線程應該被容許,在獲取共享鎖
static final int PROPAGATE = -3;
//標記着當前節點的狀態,默認狀態是0,小於0的狀態值都是有特殊做用,大於0的狀態值表示已取消
volatile int waitStatus;
//使用prev和next實現同步隊列,即雙向鏈表,當前節點的前驅節點
volatile Node prev;
//當前節點的下一節點
volatile Node next;
//當前節點對應的線程
volatile Thread thread;
//有兩種做用:一、表示下一個在Condition條件上等待的節點,調用Condition中await和signal方法,當前節點的線程是擁有獨佔鎖的線程二、表示同步隊列中的節點是共享模式仍是獨佔模式
Node nextWaiter;
//判斷當前節點是否是共享模式
final boolean isShared() {
return nextWaiter == SHARED;
}
//獲取當前節點的前驅節點,若是爲null,則拋出空指針異常
final Node predecessor() throws NullPointerException {
//當前節點的前驅節點
Node p = prev;
//若是前驅節點爲空
if (p == null)
//拋出空指針異常
throw new NullPointerException();
else
//返回當前節點的前驅節點
return p;
}
//在建立鏈表頭head,或者建立節點共享鎖標記屬性SHARED值
Node() {
}
//在addWaiter方法中使用
Node(Thread thread, Node mode) {
//當前節點的模式,是屬於共享模式,仍是獨佔模式
this.nextWaiter = mode;
//將傳入進來的線程賦值給節點屬性thread
this.thread = thread;
}
//在Condition條件中使用
Node(Thread thread, int waitStatus) {
//將傳入節點的狀態值賦值給節點屬性waitStatus
this.waitStatus = waitStatus;
//將傳入進來的線程賦值給節點屬性thread
this.thread = thread;
}
}
複製代碼
public interface Condition {
//如下方法都會詳細在ConditionObject實現類中介紹
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
//當前Condition實例的條件隊列的第一個節點
private transient Node firstWaiter;
//當前Condition實例的條件隊列的最後一個節點
private transient Node lastWaiter;
//構造函數
public ConditionObject() { }
//若是尾節點的狀態值不是CONDITION值,清除條件隊列中取消的節點,修改條件隊列的第一個節點和最後一個節點,建立新節點,將其新節點作爲條件隊列的尾節點
private Node addConditionWaiter() {
//獲取條件隊列的最後一個節點
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
//若是條件隊列中的最後一個節點不爲空,而且狀態值不是CONDITION,即最後等待節點已取消
if (t != null && t.waitStatus != Node.CONDITION) {
//移除條件隊列中的已取消的節點,從新設置firstWaiter、lastWaiter節點,詳細的能夠看下面對unlinkCancelledWaiters方法的介紹
unlinkCancelledWaiters();
//從新獲取條件隊列的最後一個節點
t = lastWaiter;
}
//建立新節點,傳入當前線程和節點的狀態值Node.CONDITION
Node node = new Node(Thread.currentThread(), Node.CONDITION);
//若是尾節點爲空
if (t == null)
//將其新節點作爲條件隊列的第一個節點
firstWaiter = node;
else
//將條件隊列中的上一個尾節點
t.nextWaiter = node;
//將其新建的節點作爲條件隊列的最後一個節點
lastWaiter = node;
//返回新建的節點
return node;
}
//只將一個條件隊列中不爲空、狀態值爲CONDITION的第一個節點加入到同步隊列中,傳入條件隊列的頭結點,將其移動同步隊列中,若是傳入的節點已取消,會將其傳入節點的下一個不爲空、狀態值爲CONDITION的節點移到同步隊列中
private void doSignal(Node first) {
do {
//傳入的節點的下一個等待節點爲空
if ( (firstWaiter = first.nextWaiter) == null)
//將其條件隊列的尾節點設置爲空
lastWaiter = null;
//加快gc回收,將其傳入節點的下一節點置爲空
first.nextWaiter = null;
//能夠看下面對transferForSignal方法的詳細介紹,將其傳入節點(狀態值爲CONDITION)移到同步隊列中,若是當前加入同步隊列節點的前置節點狀態爲已取消,或者將其前置節點的狀態值設置爲SIGNAL失敗,喚醒加入的節點對應的線程
} while (!transferForSignal(first) && //找到條件隊列中節點不爲空的而且狀態值爲CONDITION的節點加入到同步隊列中
(first = firstWaiter) != null);
}
//將其條件隊列中的全部不爲空、狀態值爲CONDITION的節點加入到同步隊列中,從傳入條件隊列的頭節點開始
private void doSignalAll(Node first) {
//將其條件隊列的頭尾節點都置爲空
lastWaiter = firstWaiter = null;
//從頭結點開始循環獲取條件隊列中的全部節點
do {
//獲取頭結點的下一節點
Node next = first.nextWaiter;
//加快gc,將其頭節點的關聯的下一節點置爲空
first.nextWaiter = null;
//能夠看下面對transferForSignal方法的詳細介紹,將其傳入節點(狀態值爲CONDITION)移到同步隊列中,若是當前加入同步隊列節點的前置節點狀態爲已取消,或者將其前置節點的狀態值設置爲SIGNAL失敗,喚醒加入的節點對應的線程
transferForSignal(first);
//將下一節點設置爲頭結點
first = next;
} while (first != null);//直到節點爲空,即條件隊列結束
}
//將已取消的節點從條件隊列中移除
private void unlinkCancelledWaiters() {
//獲取條件隊列的頭節點
Node t = firstWaiter;
//臨時變量,存放最新的不爲空、狀態值爲Node.CONDITION的節點,目的是爲了設置下一節點不爲空、狀態值爲Node.CONDITION的節點
Node trail = null;
//頭結點不爲空
while (t != null) {
//獲取頭節點的下一節點
Node next = t.nextWaiter;
//若是頭節點狀態值不是Node.CONDITION,此節點已取消
if (t.waitStatus != Node.CONDITION) {
//加快gc,此已取消節點
t.nextWaiter = null;
//若是最新的不爲空、狀態值爲CONDITION的節點爲空
if (trail == null)
//將下一節點設置爲頭結點
firstWaiter = next;
else
//將最新的不爲空、狀態值爲CONTIDION的節點和下一節點連起來
trail.nextWaiter = next;
//若是下一節點爲空,代表條件隊列已經沒有節點
if (next == null)
//將最新的不爲空、狀態值爲CONTIDION的節點賦值給尾節點
lastWaiter = trail;
}
else
//將t賦值給trail
trail = t;
將下一節點作爲頭節點
t = next;
}
}
// public methods
//將條件隊列中的不爲空、狀態值爲CONDITION頭節點移動到同步隊列中
public final void signal() {
//調用signal方法的線程,不是擁有排他鎖的線程就會拋出IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
if (!isHeldExclusively()) //isHeldExclusively方法子類得重寫,不然直接拋出UnsupportedOperationException
throw new IllegalMonitorStateException();
//獲取條件隊列的頭結點
Node first = firstWaiter;
//若是條件隊列不爲空
if (first != null)
//調用上面介紹的doSignal方法,詳細的能夠看上面的介紹,只將一個條件隊列中不爲空、狀態值爲CONDITION的第一個節點加入到同步隊列中,傳入條件隊列的頭結點,將其移動同步隊列中,若是傳入的節點已取消,會將其傳入節點的下一個不爲空、狀態值爲CONDITION的節點移到同步隊列中
doSignal(first);
}
//將條件隊列中的全部不爲空,狀態值爲CONDITION的節點移動到同步隊列中
public final void signalAll() {
/調用signalAll方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//獲取條件隊列中的頭節點
Node first = firstWaiter;
//若是頭節點不爲空,即條件隊列中存在節點
if (first != null)
//調用上面介紹的doSignalAll方法,doSignalAll方法的詳細介紹能夠看上面對此方法的介紹,將其條件隊列中的全部不爲空、狀態值爲CONDITION的節點加入到同步隊列中,從傳入條件隊列的頭節點開始
doSignalAll(first);
}
//新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待。若是線程等待期間發出中斷請求,不會產生中斷異常
public final void awaitUninterruptibly() {
//爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
Node node = addConditionWaiter();
//釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
int savedState = fullyRelease(node);
//初始化中斷標誌位爲false
boolean interrupted = false;
//循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
while (!isOnSyncQueue(node)) {
//阻塞當前線程
LockSupport.park(this);
//若是當前線程被中斷
if (Thread.interrupted())
//將中斷標誌位設置爲true
interrupted = true;
}
//節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
if (acquireQueued(node, savedState) || interrupted)
//acquireQueued方法返回true,即當前線程被中斷過,或者interruped標誌位爲true調用當前線程的interrupt方法
selfInterrupt();//Thread.currentThread().interrupt();
}
//從新中斷的標誌位
private static final int REINTERRUPT = 1;
//拋出中斷異常的標誌位
private static final int THROW_IE = -1;
//檢查傳入節點在等待時,傳入節點對應的線程是否有發生被中斷請求
//若是其餘線程沒有調用傳入節點線程的interrupt方法,即中斷請求,返回0
//若是此節點對應的線程有被中斷請求,而且中斷請求在signalled(即調用signal或signalAll)以前返回THROW_IE ,由於在調用await方法時,會新建一個節點(狀態值爲CONDITION)加入到條件隊列中,好比調用await方法傳入超時時間,阻塞線程在超時自動被喚醒,此時節點尚未被signal,可是有其餘線程調用此節點對應的線程interrupt方法
//若是中斷請求是在singal、signalAll方法以後,返回從新中斷的標誌位
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
//transferAfterCanceledWait方法,看下面的詳細介紹
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
//若是傳入進來的參數interruptMode是THROW_IE,就拋出InterruptedException異常,若是interruptMode是REINTERRUPT,則當前線程再次調用interrupt方法,再次發出中斷請求,不然就什麼都不作
private void reportInterruptAfterWait(int interruptMode) throws InterruptedException {
//若是interruptMode是THROW_IE
if (interruptMode == THROW_IE)
//拋出InterruptedException異常
throw new InterruptedException();
//若是interruptMode是REINTERRUPT,從新調用當前線程的interrupt方法,再次發出中斷請求
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
//新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待。若是線程等待期間發出中斷請求,則拋出中斷異常
public final void await() throws InterruptedException {
//若是當前線程已被中斷
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
Node node = addConditionWaiter();
//釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
int savedState = fullyRelease(node);
//線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
int interruptMode = 0;
//循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
while (!isOnSyncQueue(node)) {
//阻塞當前線程
LockSupport.park(this);
//若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
//若是當前節點的下一個節點不爲空
if (node.nextWaiter != null) // clean up if cancelled
//將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
unlinkCancelledWaiters();
//是否要拋出中斷異常,或者發出中斷請求
if (interruptMode != 0)
//能夠看上面對reportInterruptAfterWait方法的介紹
reportInterruptAfterWait(interruptMode);
}
//@param nanpsTimeout超時時間,單位爲納秒
//@return 死亡時間減去當前時間的時間戳
//新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者超時將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
public final long awaitNanos(long nanosTimeout) throws InterruptedException {
//若是線程已被中斷
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
Node node = addConditionWaiter();
//釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
int savedState = fullyRelease(node);
//獲取死亡時間,即當前時間加上傳入的超時時間
final long deadline = System.nanoTime() + nanosTimeout;
//線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
int interruptMode = 0;
//循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
while (!isOnSyncQueue(node)) {
//若是傳入的超時時間小於等於0
if (nanosTimeout <= 0L) {
//transferAfterCanceledWait方法,看下面的詳細介紹
transferAfterCancelledWait(node);
//退出循環
break;
}
//若是超時時間大於等於spinForTimeoutThreshold閾值,纔會阻塞當前線程,不然讓其線程自旋一段時間
if (nanosTimeout >= spinForTimeoutThreshold)
//超時的阻塞當前線程,this是阻塞當前線程的監控對象
LockSupport.parkNanos(this, nanosTimeout);
//若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
//退出循環
break;
//死亡時間減去當前時間,獲得超時時間
nanosTimeout = deadline - System.nanoTime();
}
//節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
//將其標誌節點interruptMode設置爲從新中斷標誌位
interruptMode = REINTERRUPT;
//若是當前節點的下一個節點不爲空
if (node.nextWaiter != null)
//將已取消的節點從條件隊列中移除,能夠看上面對unlinkCancelledWaiters方法介紹
unlinkCancelledWaiters();
//是否要拋出中斷異常,或者發出中斷請求
if (interruptMode != 0)
//能夠看上面對reportInterruptAfterWait方法的介紹
reportInterruptAfterWait(interruptMode);
//返回死亡時間減去當前時間的時間戳
return deadline - System.nanoTime();
}
//@param deadline 死亡時間
//@return 節點對應的線程被中斷是否比佔有獨佔鎖的線程調用signal、signalAll方法將當前節點從條件隊列移到同步隊列中以前,若是是返回值爲false,不然返回true,表示正常超時,而不是由中斷退出
//新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者到死亡時間將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
public final boolean awaitUntil(Date deadline) throws InterruptedException {
//死亡時間的時間戳
long abstime = deadline.getTime();
//若是線程已被中斷
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
Node node = addConditionWaiter();
//釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
int savedState = fullyRelease(node);
//是否超時的標記位
boolean timedout = false;
//線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
int interruptMode = 0;
//循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
while (!isOnSyncQueue(node)) {
//若是當前時間大於死亡時間
if (System.currentTimeMillis() > abstime) {
//transferAfterCanceledWait方法,看下面的詳細介紹
timedout = transferAfterCancelledWait(node);
//退出循環
break;
}
//阻塞當前線程直到死亡時間、或者擁有獨佔鎖的線程調用signal、signalAll方法喚醒線程
LockSupport.parkUntil(this, abstime);
//若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
//退出循環
break;
}
//節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹 if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
//將其標誌節點interruptMode設置爲從新中斷標誌位
interruptMode = REINTERRUPT;
//若是當前節點的下一個節點不爲空
if (node.nextWaiter != null)
//將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
unlinkCancelledWaiters();
//是否要拋出中斷異常,或者發出中斷請求
if (interruptMode != 0)
//能夠看上面對reportInterruptAfterWait方法的介紹
reportInterruptAfterWait(interruptMode);
//返回表示此方法是正常超時結束,仍是由中斷退出結束
return !timedout;
}
//相比awaitNanos方法超時時間更加可控,能夠傳入不一樣的超時單位
//@return 節點對應的線程被中斷是否比佔有獨佔鎖的線程調用signal、signalAll方法將當前節點從條件隊列移到同步隊列中以前,若是是返回值爲false,不然返回true,表示正常超時,而不是由中斷退出
//新建個節點加入到同步隊列中,並釋放鎖,讓當前線程阻塞等待,直到被調用signal、signalAll方法,或者超時將當前節點從條件隊列中移到同步隊列中,在同步隊列中阻塞獲得獲取鎖。若是線程等待期間發出中斷請求,則拋出中斷異常
public final boolean await(long time, TimeUnit unit) throws InterruptedException {
//將超時時間轉化爲納秒
long nanosTimeout = unit.toNanos(time);
//若是線程已被中斷
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//爲當前線程建立新的Node節點,而且將此節點加入到條件隊列中,addConditionWaiter方法能夠看上面對此方法的介紹
Node node = addConditionWaiter();
//釋放當前線程佔有的鎖,並喚醒其餘線程,fullRelease方法會在下面詳細介紹到
int savedState = fullyRelease(node);
//獲取死亡時間,即當前時間加上傳入的超時時間
final long deadline = System.nanoTime() + nanosTimeout;
//當前await方法是否正常超時結束,仍是由中斷退出結束
boolean timedout = false;
//線程中斷請求是在signal、signalAll方法將此節點加入到同步隊列以前仍是以後的標誌位
int interruptMode = 0;
//循環判斷當前新建的節點是否在同步隊列中,直到此節點在同步隊列中退出循環,不然就阻塞當前線程,isOnSyncQueue方法會在下面進行介紹
while (!isOnSyncQueue(node)) {
//若是傳入的超時時間小於等於0
if (nanosTimeout <= 0L) {
//transferAfterCanceledWait方法,看下面的詳細介紹
timedout = transferAfterCancelledWait(node);
//退出循環
break;
}
//若是超時時間大於等於spinForTimeoutThreshold閾值,纔會阻塞當前線程,不然讓其線程自旋一段時間
if (nanosTimeout >= spinForTimeoutThreshold)
//超時的阻塞當前線程,this是阻塞當前線程的監控對象
LockSupport.parkNanos(this, nanosTimeout);
//若是當前線程產生中斷請求,就跳出循環, checkInterruptWhileWaiting方法能夠看上面對此方法的介紹
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
//退出循環
break;
//返回死亡時間減去當前時間的時間戳
nanosTimeout = deadline - System.nanoTime();
}
//節點已經在同步隊列中,獲取同步鎖,只有獲得鎖才能繼續執行,不然線程繼續阻塞等待,acquireQueued方法返回當前線程是否被中斷,此方法會在下面詳細進行介紹
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
//將其標誌節點interruptMode設置爲從新中斷標誌位
interruptMode = REINTERRUPT;
//若是當前節點的下一個節點不爲空
if (node.nextWaiter != null)
//將已取消的節點從條件隊列中移除能夠看上面對unlinkCancelledWaiters方法介紹
unlinkCancelledWaiters();
//是否要拋出中斷異常,或者發出中斷請求
if (interruptMode != 0)
//能夠看上面對reportInterruptAfterWait方法的介紹
reportInterruptAfterWait(interruptMode);
//返回表示此方法是正常超時結束,仍是由中斷退出結束
return !timedout;
}
//判斷Condition實例的外部類AQS和傳入進來的AQS是否相等,判斷Condition實例是否歸屬於傳入進來的AQS
final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
// AbstractQueuedSynchronizer.this在內部類實例中常用,獲取外部類的實例
return sync == AbstractQueuedSynchronizer.this;
}
//判斷條件隊列中是否有等待的節點
protected final boolean hasWaiters() {
/調用hasWaiters方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
//判斷條件隊列中的是否有節點的狀態值爲CONDITION
if (w.waitStatus == Node.CONDITION)
//若是是直接返回true
return true;
}
//不然直接返回false
return false;
}
//獲取條件隊列中有多少個等待節點(狀態值爲CONDITION)
protected final int getWaitQueueLength() {
//調用getWaitQueueLength方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//等待節點數目
int n = 0;
//從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
//若是條件隊列中等待節點的狀態值爲CONDITION
if (w.waitStatus == Node.CONDITION)
//等待節點加1
++n;
}
//返回等待節點
return n;
}
//獲取條件隊列中全部等待節點(狀態值爲CONDITION)的線程,返回線程集合
protected final Collection<Thread> getWaitingThreads() {
//調用getWaitingThreads方法的線程,不是擁有排他鎖的線程就會IllegalMonitorStateException異常,Condition的使用只支持在排他鎖下使用
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//全部等待節點對應的線程集合
ArrayList<Thread> list = new ArrayList<Thread>();
//從條件隊列的頭節點開始,循環的獲取條件隊列中的節點
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
//若是條件隊列的等待節點的狀態值爲CONDITION
if (w.waitStatus == Node.CONDITION) {
//獲取等待節點對應的線程
Thread t = w.thread;
//若是節點對應的線程不爲空
if (t != null)
//將其線程加入到集合中
list.add(t);
}
}
//返回全部等待節點對應的線程集合
return list;
}
}複製代碼
//經過UnSafe的cas函數設置AQS的屬性head值,僅僅在enq方法中,返回設置釋放成功,使用cas保證多線程安全
private final boolean compareAndSetHead(Node update) {
//cas經過AQS實例和其屬性head偏移量,若是頭結點爲空,將其空設置爲update值
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
// 從新設置同步隊列頭結點head,只在acquire系列的方法中調用
private void setHead(Node node) {
head = node;
//當前節點對應的當前線程已經獲取到鎖了,將當前節點對應的線程置爲空
node.thread = null;
//當前節點前一個節點已經沒有意義,將當前節點對應的前置節點置爲空
node.prev = null;
}
複製代碼
//經過CAS函數設置tail值,僅僅在enq方法中調用,經過CAS函數設置tail值,保證多線程安全
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
// 向同步隊列尾插入新節點,若是隊列沒有初始化,先初始化同步隊列的頭尾節點。返回原先的同步隊列尾節點
private Node enq(final Node node) {
for (;;) {
//獲取同步隊列的尾節點
Node t = tail;
//t尾節點爲空,表示隊列爲空,先初始化隊列
if (t == null) {
// 採用CAS函數即原子操做方式,設置隊列頭head值。
// 若是成功,再將head值賦值給鏈表尾tail。若是失敗,表示head值已經被其餘線程,那麼就進入循環下一次
if (compareAndSetHead(new Node()))
tail = head;
} else {
// 新添加的node節點的前一個節點prev指向原來的隊列尾tail
node.prev = t;
// 採用CAS函數即原子操做方式,設置新隊列尾tail值。
if (compareAndSetTail(t, node)) {
// 設置老的隊列尾tail的下一個節點next指向新添加的節點node
t.next = node;
return t;
}
}
}
}
複製代碼
//獲取獨佔鎖。若是沒有立刻獲取到,線程就會阻塞等待,直到獲取到獨佔鎖。不會響應中斷異常
public final void acquire(int arg) {
//1. 當前線程先調用tryAcquire方法,嘗試獲取獨佔鎖,若是返回true,表示獲取到鎖,不須要執行acquireQueued方法。
//2. 若是tryAcquire方法獲取獨佔鎖失敗,調用acquireQueued方法,先調用addWaiter方法爲當前線程建立一個狀態爲獨佔模式的節點Node,並使用cas將其作爲同步隊列尾節點加入隊列中,
//若是當前加入節點的前置節點爲頭節點,當前線程調用tryAcquire方法去嘗試獲取鎖,若是不成功,就會根據前置節點的狀態來判斷是否讓當前線程阻塞,當前線程阻塞被喚醒。
//acquireQueued方法返回值表示在線程等待過程當中,是否有另外一個線程調用該線程的interrupt方法,發起中斷請求。
//tryAcquire是個模板方法,能夠看下面對此方法的介紹,acquireQueued方法能夠看下面對此方法的介紹
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//當前線程執行acquireQueued方法的過程當中有其餘線程調用該線程的interrupt方法,發起中斷請求,從新調用當前線程的interrupt方法,中斷請求
selfInterrupt();
}
// 嘗試去獲取獨佔鎖,當即返回。若是返回true表示獲取獨佔鎖成功,此方法爲模板方法,須要子類進行重寫,能夠看下面ReentrantReadWriteLock類中對AQS的tryAcquire方法實現
protected boolean tryAcquire(int arg) {
//拋出UnsupportedOperationException異常
throw new UnsupportedOperationException();
}
//ReentrantReadWriteLock類中對AQS的tryAcquire方法實現,詳細的介紹,會在分析ReentrantReadWriteLock源碼時進行詳細介紹
//嘗試獲取同步隊列的獨佔鎖,與非公平鎖最大的不一樣就是調用hasQueuedPredecessors()方法,hasQueuedPredecessors方法返回true,表示等待線程隊列中有一個線程在當前線程以前,根據公平鎖的規則,當前線程不能獲取鎖。
protected final boolean tryAcquire(int acquires) {
//獲取當前線程
Thread current = Thread.currentThread();
//獲取當前鎖的狀態,即AQS中的屬性值
int c = getState();
//由狀態獲取獨佔鎖的個數,鎖的狀態也是根據獨佔鎖的個數或者共享鎖的個數來進行判斷
int w = exclusiveCount(c);
//若是c==0表示當前鎖是空閒的,若是鎖狀態不等於0,代表鎖狀態有多是讀鎖或者寫鎖
if (c != 0) {
//若是獨佔鎖的個數等於0,代表當前鎖屬於共享鎖模式,直接返回失敗,若是獨佔鎖的個數不等於0,而且當前擁有獨佔鎖的線程不是當前,也是直接返回失敗
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//若是獨佔鎖的個數加上傳入進來的請求獨佔鎖個數大於MAX_COUNT,直接拋出錯誤,超過最大的獨佔鎖個數
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//不然的話更新鎖的狀態
setState(c + acquires);
//返回獲取獨佔鎖成功
return true;
}
//非公平鎖writerShouldBlock直接返回false,公平鎖writeShouldBlock會調用hasQueuedPredecessors方法
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
//返回獲取獨佔鎖失敗
return false;
//將當前線程設置爲擁有獨佔鎖的線程
setExclusiveOwnerThread(current);
//返回獲取獨佔鎖成功
return true;
}
/** * 獲取獨佔鎖的acquire系列方法,都會使用這個方法來獲取獨佔鎖 * 循環經過tryAcquire方法不斷去獲取鎖,若是沒有獲取成功,若是此節點的前置節點的狀態值爲SIGNAL * 需調用parkAndCheckInterrupt方法,讓當前線程阻塞 * @param node 想要獲取獨佔鎖鎖的節點 * @param arg 獲取獨佔鎖的個數 * @return 返回true,表示在線程等待的過程當中,線程被中斷了 */
final boolean acquireQueued(final Node node, int arg) {
//設置失敗的標誌位
boolean failed = true;
try {
//表示節點對應的線程在等待過程當中,是否被中斷的標誌位
boolean interrupted = false;
//經過死循環,直到node節點對應的線程獲取到鎖,才返回
for (;;) {
//獲取當前節點的前置節點
final Node p = node.predecessor();
//若是當前節點的前一個節點爲同步隊列的頭節點head,當前線程嘗試使用tryAcquire方法獲取鎖,若是獲取鎖成功,那麼當前線程就不須要阻塞等待,繼續執行
if (p == head && tryAcquire(arg)) {
//將節點node設置爲同步隊列的頭節點
setHead(node);
//將節點node的前置節點設置爲空,加快gc
p.next = null; // help GC
//失敗的標誌位設置爲false
failed = false;
//返回是否中斷的標誌位
return interrupted;
}
//判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法會在下面詳細進行介紹
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//若是方法parkAndCheckInterrupt的返回值爲true,代表節點對應的線程在等待時,有其餘線程調用此線程的interrupt方法,中斷請求
interrupted = true;
}
} finally {
//在獲取獨佔鎖的過程當中失敗,將當前節點從同步隊列中移除
if (failed)
//cancelAcquire方法會在下面詳細進行介紹
cancelAcquire(node);
}
}
/** * 根據前一個節點pred的狀態,來判斷當前節點對應的線程是否應該被阻塞 * @param pred : node節點的前一個節點 * @param node : 要獲取獨佔鎖的節點 * @return 返回true 表示當前線程應該被阻塞,而後調用parkAndCheckInterrupt方法來阻塞當前線程 */
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//獲取前置節點的狀態值
int ws = pred.waitStatus;
//若是前置節點的狀態值爲SIGNAL
if (ws == Node.SIGNAL)
// 若是前一個pred的狀態是Node.SIGNAL,那麼直接返回true,當前線程應該被阻塞
return true;
//若是前置節點已經取消,循環獲取不是取消的前置節點
if (ws > 0) {
// 若是前一個節點狀態是Node.CANCELLED(大於0就是CANCELLED),
// 表示前一個節點所在線程已經被喚醒了,要從CLH隊列中移除CANCELLED的節點。
// 因此從pred節點一直向前查找直到找到不是CANCELLED狀態的節點,並把它賦值給node.prev,
// 表示node節點的前一個節點已經改變。
do {
//從新賦值當前節點的前置節點
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
//不是取消的前置節點的下一節點從新賦值爲當前節點
pred.next = node;
} else {
// 此時前一個節點pred的狀態只能是0或者PROPAGATE,不多是CONDITION狀態
// CONDITION(只在condition條件隊列中節點存在,CLH同步隊列中沒有此狀態的節點)
// 將前一個節點pred的狀態設置成Node.SIGNAL,這樣在下一次循環時,就是直接阻塞當前線程
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
//返回要獲取獨佔鎖的節點對應的線程不會阻塞
return false;
}
private final boolean parkAndCheckInterrupt() {
//阻塞當前線程
LockSupport.park(this);
//當前線程被喚醒後,返回當前線程的中斷標誌位
return Thread.interrupted();
}
//將傳入進來的節點從同步隊列中移除,將傳入節點對應的線程置爲空,狀態置爲CANCELLED
private void cancelAcquire(Node node) {
//若是當前節點爲空,直接跳過
if (node == null)
return;
//將當前節點對應的線程置爲空
node.thread = null;
//獲取當前要取消節點的前置節點
Node pred = node.prev;
//循環跳過前置節點狀態爲CANNELLED的值
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
//獲取狀態不是取消的前置的節點的下一個節點,在設置前置節點的下一個節點使用到
Node predNext = pred.next;
//將當前要取消的節點狀態賦值爲CANCELLED
node.waitStatus = Node.CANCELLED;
//若是要取消節點爲尾節點,將尾節點設置爲要取消節點的前一個節點
if (node == tail && compareAndSetTail(node, pred)) {
//若是設置成功,將要取消節點的前置節點的下一個節點設置爲空
compareAndSetNext(pred, predNext, null);
} else {
int ws;
//若是前置不是頭節點,而且前置節點的狀態值爲SIGNAL,或者
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
//獲取要取消節點的下一個節點
Node next = node.next;
//要取消節點的下一個節點不爲空,而且狀態值小於等於0,即不是取消狀態值CANCELLED
if (next != null && next.waitStatus <= 0)
//將要取消節點的前置節點和要取消節點的下一節點鏈接起來
compareAndSetNext(pred, predNext, next);
} else {
//不然的話喚醒node節點的下一個節點,在下面會對unparkSuccessor方法進行詳細介紹
unparkSuccessor(node);
}
//將要取消節點的下一節點設置爲自身,加快gc
node.next = node; // help GC
}
}
//喚醒傳入節點的下一個不爲空、狀態值不是已取消CANCELLED節點對應的線程
private void unparkSuccessor(Node node) {
//獲取傳入節點的狀態
int ws = node.waitStatus;
//若是狀態小於0,將其狀態設置爲0
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//獲取傳入節點的下一節點
Node s = node.next;
//若是下一節點爲空或者是已取消節點
if (s == null || s.waitStatus > 0) {
//將下一節點置爲空
s = null;
//從同步隊列的尾節點開始,獲取不等於空,而且節點不等於傳入節點的前置節點,即從新尋找傳入節點的下一個不爲空,而且沒有取消的節點進行喚醒
for (Node t = tail; t != null && t != node; t = t.prev)
//t節點不是已取消節點
if (t.waitStatus <= 0)
//將下一節點s賦值爲t
s = t;
}
//若是下一節點s不爲空
if (s != null)
//喚醒此節點s對應的線程
LockSupport.unpark(s.thread);
}
複製代碼
//調用release方法的線程,是擁有獨佔鎖的線程,釋放獨佔鎖的操做
public final boolean release(int arg) {
//線程首先調用tryRelease方法,嘗試去釋放鎖,此方法爲模板方法,由子類具體實現
if (tryRelease(arg)) {
//若是tryRelease釋放鎖成功,獲取同步隊列的頭結點
Node h = head;
//若是頭結點不爲空,而且狀態值不等於0,無論頭結點是已取消,仍是其餘狀態
if (h != null && h.waitStatus != 0)
//喚醒頭結點的下一個不爲空,而且狀態值不爲CANCELLED的下一個節點,能夠看上面對unparkSuccessor方法的介紹
unparkSuccessor(h);
//釋放獨佔鎖成
return true;
}
//釋放獨佔鎖失敗
return false;
}
//AQS的模板方法,由具體的子類實現
protected boolean tryRelease(int arg) {
//拋出UnsupportedOperationException異常
throw new UnsupportedOperationException();
}
//ReentrantReadWriteLock中Sync的tryRelease方法實現
protected final boolean tryRelease(int releases) {
//判斷當前嘗試釋放鎖的線程,是不是擁有獨佔鎖的線程,若是不是拋出IllegalMonitorStateException異常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//將其鎖的狀態值減去要釋放的獨佔鎖的個數
int nextc = getState() - releases;
//若是nextc爲0,表示獨佔鎖是否成功
boolean free = exclusiveCount(nextc) == 0;
if (free)
//若是鎖釋放成功,將其記錄擁有獨佔鎖的線程的記錄置爲空
setExclusiveOwnerThread(null);
//設置鎖的狀態
setState(nextc);
//返回獨佔鎖釋放是否成功
return free;
}
複製代碼
//獲取共享鎖,不響應中斷,不會拋出中斷異常
public final void acquireShared(int arg) {
//當前線程調用tryAcquireShared嘗試去獲取共享鎖,若是返回值小於0表示獲取共享鎖失敗
if (tryAcquireShared(arg) < 0)
// 調用doAcquireShared方法去獲取共享鎖,tryAcquireShared、doAcquireShared方法會在下面詳細進行介紹
doAcquireShared(arg);
}
//嘗試獲取共享鎖,AQS的模板方法,由具體的子類進行實現
protected int tryAcquireShared(int arg) {
//拋出UnsupportedOperationException異常
throw new UnsupportedOperationException();
}
//ReentrantReadWriteLock類對tryAcquireShared方法的實現,會在ReentrantReadWriteLock源碼的分析中進行詳細的介紹
protected final int tryAcquireShared(int unused) {
//獲取當前線程
Thread current = Thread.currentThread();
//獲取鎖的狀態
int c = getState();
//exclusiveCount根據鎖的狀態獲取獨佔鎖的個數若是不等於0,而且擁有此獨佔鎖的線程不是當前線程,直接返回-1失敗
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//根據鎖的狀態獲取共享鎖的個數
int r = sharedCount(c);
//獲取共享鎖,當前線程是否須要阻塞,readerShouldBlock方法分爲公平鎖和非公平鎖的不一樣實現,公平鎖會調用hasQueuedPredecessors方法,判斷同步隊列中前面是否有節點,有阻塞,非公平鎖會
//調用apparentlyFirstQueuedIsExclusive方法,判斷頭節點的狀態是不是獨佔鎖模式,若是是阻塞當前線程,不然繼續執行。而且共享鎖的個數得小於MAX_COUNT
if (!readerShouldBlock() &&
r < MAX_COUNT &&
//使用cas將當前鎖的狀態加上65535,即高16位存放共享鎖的個數
compareAndSetState(c, c + SHARED_UNIT)) {
//若是原先共享鎖的個數爲0
if (r == 0) {
//將當前線程賦值給第一個獲取共享鎖的線程firstReader
firstReader = current;
//當前線程持有的共享鎖個數
firstReaderHoldCount = 1;
} else if (firstReader == current) {//鎖的狀態共享鎖原先就有被獲取,而且第一個持有的線程是當前線程,firstReaderHoldCount++操做,持有共享鎖個數加1操做
//第一個獲取共享鎖的線程持有的共享鎖個數加1操做
firstReaderHoldCount++;
} else {
//獲取上一次緩存的線程的HoldCounter,HoldCounter實例是存放一個線程已獲取的共享鎖個數,及線程id
HoldCounter rh = cachedHoldCounter;
//上一次緩存的HoldCounter實例爲空,或者HoldCounter實例裏的線程id和當期線程id不相等
if (rh == null || rh.tid != getThreadId(current))
//從新獲取當前線程對應的HoldCounter實例
cachedHoldCounter = rh = readHolds.get();
//若是當前線程對應的HoldCounter實例的線程獲取共享鎖的個數爲0,從新將rh設置到ThreadLocal,ThreadLocal不清楚的能夠看下個人另外一篇對此的源碼分析
else if (rh.count == 0)
readHolds.set(rh);
//不然線程對應的HoldCounter實例的線程已獲取的共享鎖個數進行加1操做
rh.count++;
}
//返回1,表示獲取共享鎖成功
return 1;
}
//fullTryAcquireShared能夠看下面對此方法的介紹
return fullTryAcquireShared(current);
}
//ReentrantReadWriteLock類的fullTryAcquireShared方法,詳細的會再ReentrantReadWriteLock源碼分析進行介紹
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
//死循環的獲取共享鎖
for (;;) {
//獲取鎖的狀態
int c = getState();
//若是當前鎖狀態是獨佔鎖,而且擁有獨佔鎖的線程不是當前線程直接返回-1失敗
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
//當前線程是否須要阻塞,readerShouldBlock方法分爲公平鎖和非公平鎖的不一樣實現,公平鎖會調用hasQueuedPredecessors方法,判斷同步隊列中前面是否有節點,有阻塞,非公平鎖會調用apparentlyFirstQueuedIsExclusive方法,判斷頭節點的狀態是不是獨佔鎖模式,若是是阻塞當前線程
} else if (readerShouldBlock()) {
//若是當前線程就是第一個獲取共享鎖的線程,不作任何操做
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
//獲取上一次緩存的HoldCounter實例
rh = cachedHoldCounter;
//HoldCounter實例爲空,而且HoldCounter實例不屬於當前線程
if (rh == null || rh.tid != getThreadId(current)) {
//獲取當前線程對應的HoldCounter實例
rh = readHolds.get();
//若是當前線程獲取共享鎖個數爲0,將HoldCounter實例從ThreadLocal中移除
if (rh.count == 0)
readHolds.remove();
}
}
//若是當前線程對應的HoldCounter實例的屬性count等於0,即當前線程沒有獲取到共享鎖,count當前線程獲取的共享鎖個數
if (rh.count == 0)
//返回-1失敗
return -1;
}
}
//當前共享鎖的個數大於MAX_COUNT,直接拋出一個錯誤
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//共享鎖是使用狀態的高16位進行存儲,爲此加共享鎖加65535
if (compareAndSetState(c, c + SHARED_UNIT)) {
//若是共享鎖的個數爲0,即沒有獲取過共享鎖
if (sharedCount(c) == 0) {
//將第一個獲取共享鎖的標識屬性firstReader賦值爲當前線程
firstReader = current;
//獲取共享鎖的個數爲1
firstReaderHoldCount = 1;
//鎖的狀態共享鎖原先就有被獲取,而且第一個持有的線程是當前線程,firstReaderHoldCount++操做,持有共享鎖個數加1操做
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
//若是HoldCounter實例爲空
if (rh == null)
//從緩存中獲取上一次的HoldCounter實例
rh = cachedHoldCounter;
//HoldCounter實例爲空,而且不屬於當前線程
if (rh == null || rh.tid != getThreadId(current))
//從ThreadLocal中從新獲取HoldCounter實例
rh = readHolds.get();
//若是當前線程對應的HoldCounter實例的線程獲取共享鎖的個數爲0,從新將rh設置到ThreadLocal,ThreadLocal不清楚的能夠看下個人另外一篇對此的源碼分析
else if (rh.count == 0)
readHolds.set(rh);
//不然線程對應的HoldCounter實例的線程已獲取的共享鎖個數進行加1操做
rh.count++;
//將緩存賦值爲當前線程的HoldCounter
cachedHoldCounter = rh; // cache for release
}
//返回1表示獲取共享鎖成功
return 1;
}
}
}
//死循環獲取共享鎖,根據當前節點的前一個節點狀態來判斷當前線程是否應該阻塞,直到獲取到共享鎖
private void doAcquireShared(int arg) {
//往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
final Node node = addWaiter(Node.SHARED);
//獲取共享鎖是否成功
boolean failed = true;
try {
//當前線程在獲取共享鎖的過程當中是否被中斷的標誌位
boolean interrupted = false;
for (;;) {
//獲取當前節點的前一個節點
final Node p = node.predecessor();
//若是當前節點的前置節點爲表頭
if (p == head) {
//使用上面介紹的tryAcquireShared嘗試獲取共享鎖
int r = tryAcquireShared(arg);
//
if (r >= 0) {
//能夠看下面對setHeadAndPropagate方法的介紹
setHeadAndPropagate(node, r);
//將當前節點的前置節點下一個節點置爲空
p.next = null; // help GC
//若是發生中斷請求
if (interrupted)
selfInterrupt();
//獲取共享鎖成功
failed = false;
//直接返回
return;
}
}
//判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//parkAndCheckInterrupt返回值是否有中斷請求
interrupted = true;
}
} finally {
//若是失敗
if (failed)
//將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹
cancelAcquire(node);
}
}
// 從新設置CLH隊列頭,若是CLH隊列頭的下一個節點爲null或者共享模式,那麼就要喚醒共享鎖上等待的線程
private void setHeadAndPropagate(Node node, int propagate) {
//獲取同步隊列的頭節點
Node h = head; // Record old head for check below
//將傳入進來的節點設置爲同步隊列的表頭,將傳入進來的前置節點和線程都置爲空
setHead(node);
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
// 獲取新的CLH隊列頭的下一個節點s
Node s = node.next;
// 若是節點s是空或者共享模式節點,那麼就要喚醒共享鎖上等待的線程
if (s == null || s.isShared())
//在下面共享鎖的釋放會對此方法進行介紹
doReleaseShared();
}
}
//若是當前線程在獲取共享鎖的過程當中,有其餘線程調用當前線程的interrupt方法,中斷請求,會拋出中斷異常
public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
//若是當前線程被其餘線程發起中斷請求
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//tryAcquireShared能夠看上面對此方法的介紹
if (tryAcquireShared(arg) < 0)
//能夠看下面對doAcquireSharedInterruptibly的介紹
doAcquireSharedInterruptibly(arg);
}
//超時的獲取共享鎖,而且響應中斷請求,拋出中斷異常
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
//若是當前線程被其餘線程發起中斷請求
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//tryAcquireShared能夠看上面對此方法的介紹
return tryAcquireShared(arg) >= 0 ||
//能夠看下面對doAcquireSharedNanos的介紹
doAcquireSharedNanos(arg, nanosTimeout);
}
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
//往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
final Node node = addWaiter(Node.SHARED);
//執行是否失敗的標誌位,若是失敗會將此節點從同步隊列中移除
boolean failed = true;
try {
//死循環的獲取共享鎖,除非獲取共享鎖成功,獲取線程在阻塞的過程當中,被中斷,拋出中斷異常
for (;;) {
//獲取當前節點的前一個節點
final Node p = node.predecessor();
//若是當前節點的前置節點爲表頭
if (p == head) {
//使用上面介紹的tryAcquireShared嘗試獲取共享鎖
int r = tryAcquireShared(arg);
if (r >= 0) {
//能夠看上面對setHeadAndPropagate方法的介紹
setHeadAndPropagate(node, r);
//將當前節點的前置節點下一個節點置爲空
p.next = null; // help GC
//獲取共享鎖成功
failed = false;
//直接返回
return;
}
}
//判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//若是線程在阻塞的過程當中,有其餘線程調用當前線程的interrupt方法,中斷請求,拋出中斷異常
throw new InterruptedException();
}
} finally {
//若是失敗
if (failed)
//將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹
cancelAcquire(node);
}
}
//支持中斷,會拋出中斷異常,返回值是否獲取共享鎖成功
private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
//若是傳入進來的超時時間小於等於0直接返回失敗
if (nanosTimeout <= 0L)
return false;
//死亡時間,當前時間加上超市時間
final long deadline = System.nanoTime() + nanosTimeout;
//往同步隊列中從尾節點加入一個模式爲共享鎖的節點,看上面對addWaiter方法的介紹
final Node node = addWaiter(Node.SHARED);
//執行是否失敗的標誌位,若是失敗會將此節點從同步隊列中移除
boolean failed = true;
try {
for (;;) {
//獲取當前節點的前一個節點
final Node p = node.predecessor();
//若是當前節點的前置節點爲表頭
if (p == head) {
//使用上面介紹的tryAcquireShared嘗試獲取共享鎖
int r = tryAcquireShared(arg);
if (r >= 0) {
//能夠看上面對setHeadAndPropagate方法的介紹
setHeadAndPropagate(node, r);
//將當前節點的前置節點下一個節點置爲空
p.next = null; // help GC
//獲取共享鎖成功
failed = false;
//直接返回
return;
}
}
//獲取剩餘的超時時間
nanosTimeout = deadline - System.nanoTime();
//若是在超時時間仍是沒有獲取到共享鎖,直接返回失敗
if (nanosTimeout <= 0L)
return false;
//判斷當前節點的前置節點的狀態值是否爲SIGNAL,若是是調用parkAndCheckInterrupt方法阻塞當前線程,shouldParkAfterFailedAcquire和parkAndCheckInterrupt方法能夠看上面對這兩個方法的詳細介紹
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold) //而且超時時間大於必定的閾值不然讓其自旋一段時間
//使用LockSupport阻塞當前線程
LockSupport.parkNanos(this, nanosTimeout);
//若是當前線程在阻塞過程當中被中斷
if (Thread.interrupted())
//直接拋出中斷異常
throw new InterruptedException();
}
} finally {
//若是失敗
if (failed)
//將當前節點從同步隊列中移除,能夠看上面對cancelAcquire方法的介紹
cancelAcquire(node);
}
}
複製代碼
//釋放共享鎖
public final boolean releaseShared(int arg) {
//嘗試釋放共享鎖
if (tryReleaseShared(arg)) {
//喚醒等待共享鎖的線程
doReleaseShared();
return true;
}
return false;
}
//嘗試去釋放共享鎖,AQS的模板方法,由不一樣的子類進行實現
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
//ReentrantReadWriteLock類的tryReleaseShared方法實現
protected final boolean tryReleaseShared(int unused) {
//獲取當前線程
Thread current = Thread.currentThread();
//若是當前線程是第一個獲取共享鎖的線程
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
//第一個獲取共享鎖的線程持有的共享鎖數等於1,將firstReader置爲空
if (firstReaderHoldCount == 1)
firstReader = null;
else
//第一個獲取共享鎖的線程持有的共享鎖數作減1操做
firstReaderHoldCount--;
} else {
//獲取上一次緩存的HoldCounter實例
HoldCounter rh = cachedHoldCounter;
//HoldCounter實例rh爲空,或者rh不屬於當前線程
if (rh == null || rh.tid != getThreadId(current))
//從新獲取當前線程的HoldCounter實例
rh = readHolds.get();
//若是當前線程持有的共享鎖個數
int count = rh.count;
if (count <= 1) {
//從ThreadLocal中移除當前線程的HoldCounter實例
readHolds.remove();
//count <= 0表示當前線程就沒有獲取到讀鎖(共享鎖),這裏釋放就拋出異常
if (count <= 0)
throw unmatchedUnlockException();
}
//當前線程的持有共享鎖個數作減1操做
--rh.count;
}
//死循環的釋放鎖,若是當前鎖的共享鎖個數爲0,返回true,代表共享鎖釋放成功
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
//喚醒等待共享鎖的線程
private void doReleaseShared() {
for (;;) {
// 將同步隊列頭賦值給節點h
Node h = head;
// 若是節點h不爲null,且不等於同步隊列尾
if (h != null && h != tail) {
// 獲得節點h的狀態
int ws = h.waitStatus;
//若是狀態是Node.SIGNAL,就要喚醒節點h後繼節點的線程
if (ws == Node.SIGNAL) {
// 將節點h的狀態設置成0,若是設置失敗,就繼續循環,再試一次。
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
// 喚醒節點h後繼節點的線程
unparkSuccessor(h);
}
// 若是節點h的狀態是0,就設置ws的狀態是PROPAGATE。
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
// 若是同步隊列頭head節點發生改變,繼續循環,
// 若是沒有改變,就跳出循環
if (h == head)
break;
}
}複製代碼