AQS是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架调炬,能夠?qū)崿F(xiàn)大部分同步需求的基礎(chǔ)语盈,AQS基于volatile變量提供的鎖的內(nèi)存語義和CAS原子操作指令來實(shí)現(xiàn)多線程的同步機(jī)制。state同步狀態(tài)量為整型缰泡,并發(fā)locks包中還提供了AbstractQueuedSynchronizer的鏡像long類型state版本AbstractQueuedLongSynchronizer刀荒,支持更多的線程獲取同步狀態(tài)。
原理解析
等待隊(duì)列節(jié)點(diǎn)
static final class Node {
/**共享節(jié)點(diǎn)模式*/
static final Node SHARED = new Node();
/** 獨(dú)占節(jié)點(diǎn)模式 */
static final Node EXCLUSIVE = null;
/** waitStatus 狀態(tài)的常量表示 */
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
// 前繼節(jié)點(diǎn)
volatile Node prev;
// 后繼節(jié)點(diǎn)
volatile Node next;
// 入隊(duì)的線程
volatile Thread thread;
// 等待在condition上的下一個(gè)節(jié)點(diǎn)(獨(dú)占模式)或者是特定的值SHARED用來標(biāo)示此節(jié)點(diǎn)是共享模式
Node nextWaiter;
// 如果當(dāng)前節(jié)點(diǎn)等待在共享模式上則返回true
final boolean isShared() {
return nextWaiter == SHARED;
}
// 返回前繼節(jié)點(diǎn)棘钞,如果前繼節(jié)點(diǎn)為null則拋出異常
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
// 默認(rèn)構(gòu)造函數(shù):用來初始化頭節(jié)點(diǎn)或者SHARED共享模式標(biāo)志
Node() {
}
// 被addWaiter調(diào)用
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
// 被Condition使用
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
等待狀態(tài)詳解:
- CANCELLED 取消狀態(tài)
由于在等待隊(duì)列中等待的線程等待超時(shí)或者被中斷缠借,需要從等待隊(duì)列中取消等待,之后這個(gè)狀態(tài)的節(jié)點(diǎn)狀態(tài)將不再發(fā)生變化武翎。處于這種狀態(tài)的節(jié)點(diǎn)會被踢出隊(duì)列烈炭,被GC回收
- SIGNAL 通知狀態(tài)
當(dāng)前節(jié)點(diǎn)的線程釋放了同步狀態(tài)或者被取消,將會喚醒后繼等待(阻塞)的節(jié)點(diǎn)宝恶,使得后繼節(jié)點(diǎn)的線程得以運(yùn)行符隙。
- CONDITION 條件等待狀態(tài)
當(dāng)前節(jié)點(diǎn)等待(阻塞)在Condition上,當(dāng)其他線程對Condition調(diào)用signal方法后垫毙,該節(jié)點(diǎn)將會從等待隊(duì)列中轉(zhuǎn)移到同步隊(duì)列中霹疫,加入對同步狀態(tài)的獲取中。
- PROPAGATE 傳播狀態(tài)
表示在下一次共享模式同步狀態(tài)獲取將會無條件地被傳播下去综芥。使用共享模式的head節(jié)點(diǎn)有可能處于這種狀態(tài)丽蝎。
- INITIAL 初始狀態(tài)
新建節(jié)點(diǎn)處于這種狀態(tài)
分析思路:分析主要方法的調(diào)用流程,洞察實(shí)現(xiàn)原理
獨(dú)占式同步狀態(tài)獲取與釋放
主要方法是acquire和release
acquire方法流程
- acquire 獨(dú)占式同步狀態(tài)的獲取膀藐,獲取過程中忽略中斷屠阻,但是最終會設(shè)置中斷標(biāo)志
/**
* 向外提供的獨(dú)占式獲取同步狀態(tài)的方法
*
*
* 第一次嘗試獲取同步狀態(tài),成功則返回额各,
* 失敗則將當(dāng)前線程構(gòu)造成節(jié)點(diǎn)并添加到等待隊(duì)列
* 并死循環(huán)獲取同步狀態(tài)
* 如果線程被中斷則設(shè)置當(dāng)前線程的中斷狀態(tài)
*/
public final void acquire(long arg) {
// 第一次嘗試獲取同步狀態(tài)国觉,成功則返回
if (!tryAcquire(arg) &&
// 失敗則構(gòu)造節(jié)點(diǎn),入隊(duì)虾啦,死循環(huán)獲取
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 設(shè)置中斷標(biāo)志
selfInterrupt();
}
- tryAcquire
/**
* 需要重寫的自定義方法麻诀,該方法需要保證線程
* 安全的獲取同步狀態(tài)(CAS痕寓,用AQS提供的方法實(shí)現(xiàn))
* @return 獲取成功則返回true
*/
protected boolean tryAcquire(long arg) {
throw new UnsupportedOperationException();
}
- addWaiter
/**
* 為當(dāng)前線程以及給定模式創(chuàng)建新節(jié)點(diǎn)并入隊(duì)
*
* @param mode 節(jié)點(diǎn)等待模式
* @return node 新添加的節(jié)點(diǎn)
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// 進(jìn)行一次入隊(duì)嘗試,失敗則有enq的死循環(huán)CAS來保證最后能入隊(duì)
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 循環(huán)CAS來保證最后能入隊(duì)
enq(node);
return node; // 返回新添加的等待節(jié)點(diǎn)
}
- enq
/**
* 線程安全地插入節(jié)點(diǎn)到等待隊(duì)列中(死循環(huán)CAS)
* 當(dāng)尾節(jié)點(diǎn)為null時(shí)插入前需要初始化頭結(jié)點(diǎn)
* @param node 入隊(duì)的節(jié)點(diǎn)
* @return t 入隊(duì)節(jié)點(diǎn)的前繼節(jié)點(diǎn)
*/
private Node enq(final Node node) {
// 循環(huán)CAS將節(jié)點(diǎn)入隊(duì)
for (;;) {
Node t = tail;
// 當(dāng)尾節(jié)點(diǎn)為null時(shí)表明:則說明等待隊(duì)列為空
// 需要初始化一個(gè)頭尾相等的等待隊(duì)列蝇闭。
// head和tail的延遲初始化呻率。
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))// 初始化需要 CAS 設(shè)置頭節(jié)點(diǎn)
tail = head; // 頭尾相等
}
// 尾節(jié)點(diǎn)不為null,說明等待隊(duì)列不為空呻引,可以插入
else {
node.prev = t; // 插入節(jié)點(diǎn)和尾節(jié)點(diǎn)前向關(guān)聯(lián)礼仗,防止斷裂
if (compareAndSetTail(t, node)) { // CAS 插入尾節(jié)點(diǎn)
t.next = node; // 后向關(guān)聯(lián)
return t; // 返回插入節(jié)點(diǎn)的前繼節(jié)點(diǎn)
}
}
}
}
- acquireQueued
/**
* 每一個(gè)加入等待隊(duì)列的節(jié)點(diǎn)線程通過自旋獲取同步狀態(tài)
* 判斷自己的前繼節(jié)點(diǎn)是否為頭結(jié)點(diǎn),如果是則嘗試獲取同步狀態(tài)
* 成功則返回逻悠,否則根據(jù)前繼節(jié)點(diǎn)是否為SIGNAL來阻塞線程
*
* @param node 入隊(duì)的節(jié)點(diǎn)
* @return 等待過程中發(fā)生中斷則返回true
*/
final boolean acquireQueued(final Node node, long arg) {
// 獲取失敗標(biāo)志初始化為true(第一次確實(shí)失敗了)
boolean failed = true;
try {
// 線程中斷標(biāo)志
boolean interrupted = false;
// 自旋獲取同步狀態(tài)
for (;;) {
// 如果為null拋出異常
final Node p = node.predecessor();
// 判斷前繼節(jié)點(diǎn)是否為head節(jié)點(diǎn)藐守,
// 如果是則嘗試獲取同步狀態(tài)
if (p == head && tryAcquire(arg)) {
// 成功獲取同步狀態(tài),則將當(dāng)前節(jié)點(diǎn)設(shè)置為head結(jié)點(diǎn)
// 在獨(dú)占模式下設(shè)置head節(jié)點(diǎn)蹂风,不需要考慮線程問題,
// 因?yàn)橥粫r(shí)刻只有一個(gè)線程能獲取同步狀態(tài)
setHead(node);
// head節(jié)點(diǎn)的prev和thread引用為null乾蓬,如果next引用也為null則將被GC
// 斷開head節(jié)點(diǎn)的所有引用惠啄,幫助GC
p.next = null;
failed = false;
return interrupted;
}
// 如果當(dāng)前節(jié)點(diǎn)前繼不是head節(jié)點(diǎn),或者是前繼節(jié)點(diǎn)head節(jié)點(diǎn)但是
// 沒有獲取到同步狀態(tài)
// 而且如果需要阻塞線程任内,則阻塞線程撵渡,并將線程中斷標(biāo)志
// 重置,并設(shè)置interrupted為重置前的中斷狀態(tài)
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
}
// 前面死循環(huán)自旋死嗦,只有成功獲取才能退出循環(huán)趋距,而且還會設(shè)置failed為false
// 所以我在想什么時(shí)候failed為true,并執(zhí)行cancelAcquire操作
// 后來發(fā)現(xiàn)在 node.predecessor() 方法中當(dāng)前繼節(jié)點(diǎn)為null時(shí)會拋出
// NullPonitException異常越除,看來當(dāng)前節(jié)點(diǎn)沒有前繼節(jié)點(diǎn)時(shí)需要取消獲取的操作
// 這是由于取消狀態(tài)的節(jié)點(diǎn)從等待隊(duì)列中移除节腐,沒有關(guān)聯(lián)的前節(jié)點(diǎn)而導(dǎo)致,
// 因?yàn)閔ead節(jié)點(diǎn)一定是獲取到同步狀態(tài)的線程摘盆,在成功獲取同步狀態(tài)線程會
// 立刻返回翼雀。
finally {
if (failed)
cancelAcquire(node);
}
}
值得注意的是,在獲取同步狀態(tài)的主循環(huán)中孩擂,僅僅是記錄中斷狀態(tài)狼渊,然后將中斷狀態(tài)返回,在acquire中則根據(jù)這個(gè)中斷狀態(tài)类垦,在獲取成功返回前設(shè)置這個(gè)中斷標(biāo)志狈邑,經(jīng)歷如下過程:
**parkAndCheckInterrupt重置返回→acquireQueued記錄并返回→acquire重新設(shè)置 **
成功獲取同步狀態(tài)的線程在這個(gè)方法里** 只是調(diào)用setHead設(shè)置head節(jié)點(diǎn),但是并沒有修改head的等待狀態(tài)蚤认。米苹,當(dāng)釋放同步狀態(tài)時(shí)會將head節(jié)點(diǎn)狀態(tài)CAS設(shè)置為初始狀態(tài),然后喚醒后繼阻塞的線程烙懦,被喚醒的線程會檢查前繼節(jié)點(diǎn)以及其狀態(tài)驱入,當(dāng)獲取失敵喑础(隱含有線程成功獲取同步狀態(tài),并設(shè)置了新的head)**會確保前繼節(jié)點(diǎn)的狀態(tài)為SIGNAL
什么時(shí)候會執(zhí)行finally語句塊的內(nèi)容亏较?
比如fullyRelease方式失敗莺褒,會將節(jié)點(diǎn)狀態(tài)設(shè)置為CANCEL,詳解見上面代碼注釋
- setHead
/**
* 將給定的節(jié)點(diǎn)設(shè)置為頭結(jié)點(diǎn)
* 等待隊(duì)列初始化后雪情,只有獲得同步狀態(tài)的線程才能設(shè)置頭結(jié)點(diǎn)
* 所以不需要循環(huán)CAS來設(shè)置頭結(jié)點(diǎn)
* head節(jié)點(diǎn)只是獲得同步狀態(tài)的線程的通知阻塞線程的載體
* @param node 新的head節(jié)點(diǎn)
*/
private void setHead(Node node) {
head = node;
node.thread = null; // 并不保存獲得同步狀態(tài)線程信息
node.prev = null; // 前繼節(jié)點(diǎn)為null
}
獨(dú)占模式下獲取到同步狀態(tài)的線程的節(jié)點(diǎn)的狀態(tài)不會在setHead之后發(fā)生變化遵岩,也不會影響后繼節(jié)點(diǎn)。但是在共享模式下會將發(fā)生變化巡通,見共享模式
- shouldParkAfterFailedAcquire
/**
* 檢查并設(shè)置獲取失敗的節(jié)點(diǎn)的等待狀態(tài)
* 新加入的節(jié)點(diǎn)要么獲取同步狀態(tài)要么阻塞尘执,
* 如果當(dāng)前節(jié)點(diǎn)是head結(jié)點(diǎn),則tryAcquire獲取同步狀態(tài)
* 如果當(dāng)前節(jié)點(diǎn)不是head結(jié)點(diǎn)宴凉,則需要判斷是否需要阻塞
* 這個(gè)方法是整個(gè)acquire循環(huán)中主要的信號控制
* @param pred node的前繼節(jié)點(diǎn)
* @param node
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
// 前繼節(jié)點(diǎn)的等待狀態(tài)
int ws = pred.waitStatus;
// 如果前繼節(jié)點(diǎn)為通知狀態(tài)
// 表示后繼阻塞的節(jié)點(diǎn)能夠被前繼節(jié)點(diǎn)喚醒(釋放或取消)誊锭,所以大膽的阻塞當(dāng)前節(jié)點(diǎn)
// 則返回true,表示應(yīng)該阻塞當(dāng)前節(jié)點(diǎn)
if (ws == Node.SIGNAL)
return true;
// 如果為取消狀態(tài)弥锄,則將當(dāng)前節(jié)點(diǎn)的前繼節(jié)點(diǎn)設(shè)置為
// 向前遍歷不為取消狀態(tài)的第一個(gè)節(jié)點(diǎn)丧靡,并關(guān)聯(lián)彼此。
// 其實(shí)相當(dāng)于在等待隊(duì)列中刪除取消狀態(tài)的節(jié)點(diǎn)籽暇。
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
}
// 如果前繼節(jié)點(diǎn)不為取消狀態(tài)温治,則表明需要一個(gè)通知的信號
// 設(shè)置前繼節(jié)點(diǎn)為通知狀態(tài),但是不會阻塞線程戒悠。
// 并由調(diào)用者在下一次嘗試保證
// 在阻塞之前不能進(jìn)行獲取同步狀態(tài)的操作
else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
對當(dāng)前節(jié)點(diǎn)的前繼節(jié)點(diǎn)進(jìn)行判斷:
- 當(dāng)為狀態(tài)為SIGNAL時(shí)則返回true熬荆,
- 當(dāng)為CANCEL時(shí)則刪除當(dāng)前節(jié)點(diǎn)的狀態(tài)為CANCEL的前繼節(jié)點(diǎn),直到第一個(gè)非CANCEL節(jié)點(diǎn)并關(guān)聯(lián)彼此绸狐。
- 狀態(tài)為INITIAL卤恳、PROPAGATE和CONDITION時(shí),則將前繼節(jié)點(diǎn)設(shè)置為SIGNAL六孵,確保前繼節(jié)點(diǎn)能夠通知到當(dāng)前節(jié)點(diǎn)纬黎,并返回false,不阻塞劫窒,進(jìn)行下一次循環(huán)獲取本今。
前繼節(jié)點(diǎn)為SIGNAL狀態(tài)的線程都需要阻塞,當(dāng)前繼節(jié)點(diǎn)不為SIGNAL主巍,要設(shè)置為SIGNAL冠息,即始終保持前繼節(jié)點(diǎn)的SIGNAL狀態(tài)。
- parkAndCheckInterrupt
/**
* 阻塞當(dāng)前線程
* @return 如果當(dāng)前線程被中斷則返回true
*/
private final boolean parkAndCheckInterrupt() {
// 參數(shù)this為阻塞對象孕索,用來標(biāo)識當(dāng)前線程在等待的對象逛艰,
// 該對象用來問題排查和系統(tǒng)監(jiān)控
LockSupport.park(this);
// 清除中斷標(biāo)志,并返回清除之前的中斷狀態(tài)
return Thread.interrupted();
}
- selfInterrupt
/**
* 設(shè)置當(dāng)前線程的中斷標(biāo)志
*/
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
- cancelAcquire
/**
* 取消CANCEL狀態(tài)的節(jié)點(diǎn)嘗試的獲取操作
*
* @param node CANCEL狀態(tài)的節(jié)點(diǎn)
*/
private void cancelAcquire(Node node) {
// 節(jié)點(diǎn)為null則返回
if (node == null)
return;
// 清除線程引用搞旭,幫助GC
node.thread = null;
// 跳過取消的前繼節(jié)點(diǎn)
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 保存前繼節(jié)點(diǎn)的后繼節(jié)點(diǎn)引用
Node predNext = pred.next;
// 設(shè)置當(dāng)前節(jié)點(diǎn)的狀態(tài)為取消狀態(tài)
node.waitStatus = Node.CANCELLED;
// 如果當(dāng)前節(jié)點(diǎn)為尾節(jié)點(diǎn)散怖,則將前繼節(jié)點(diǎn)設(shè)置為尾節(jié)點(diǎn)
// 并將尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)設(shè)置為null
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
}
// 如果當(dāng)前節(jié)點(diǎn)不為尾節(jié)點(diǎn)菇绵,或者為尾節(jié)點(diǎn),但是設(shè)置尾節(jié)點(diǎn)時(shí)失敗镇眷,
// 此時(shí)當(dāng)前節(jié)點(diǎn)可能存在后繼節(jié)點(diǎn)咬最,替代它成為尾節(jié)點(diǎn)
else {
// 如果后繼節(jié)點(diǎn)能夠被通知,則將當(dāng)前節(jié)點(diǎn)的前繼節(jié)點(diǎn)的后繼節(jié)點(diǎn)設(shè)置
// 為當(dāng)前節(jié)點(diǎn)后繼節(jié)點(diǎn)欠动,否則直接喚醒當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)永乌。
int ws;
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
將取消獲取的節(jié)點(diǎn)的狀態(tài)設(shè)置為CANCEL,并剔除具伍,然后確保調(diào)整后的節(jié)點(diǎn)的前繼節(jié)點(diǎn)為SIGNAL狀態(tài)翅雏。
release方法流程
- release
/**
* 釋放同步狀態(tài)
* @return tryRelease返回true則返回true
*/
public final boolean release(long arg) {
// 修改同步狀態(tài)成功
if (tryRelease(arg)) {
Node h = head;
// 如果head節(jié)點(diǎn)不為null,而且狀態(tài)不為初始狀態(tài)
// 則喚醒head后繼節(jié)點(diǎn)
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
獨(dú)占模式下人芽,只有獲取到同步狀態(tài)的線程才能釋放望几,所以不存在線程安全的問題
- tryRelease
/**
* 獨(dú)占模式釋放同步狀態(tài),不需要保證線程并發(fā)
* 需要實(shí)現(xiàn)此方法萤厅,為釋放同步狀態(tài)修改state值
*/
protected boolean tryRelease(long arg) {
throw new UnsupportedOperationException();
}
- unparkSuccessor
/**
* 喚醒node節(jié)點(diǎn)存在的一個(gè)后繼節(jié)點(diǎn)
* 注意:喚醒的節(jié)點(diǎn)并不一定能獲取到同步狀態(tài)橄妆,
* 所以setHead方法并在這里調(diào)用,而是在acquireQueued
* 中成功獲取同步狀態(tài)后調(diào)用
*/
private void unparkSuccessor(Node node) {
/*
* 當(dāng)節(jié)點(diǎn)的等待狀態(tài)waitStatus為負(fù)值時(shí)祈坠,比如可能通知后繼阻塞節(jié)點(diǎn)執(zhí)行等,
* 則需要重置狀態(tài)值為初始值矢劲,這里沒有采用循環(huán)CAS設(shè)置赦拘,即使這一次嘗試由于
* CAS失敗或者等待線程修改狀態(tài)而導(dǎo)致失敗都是允許的。
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* 如果后繼節(jié)點(diǎn)為null或者為CANCELLED取消狀態(tài)則從尾節(jié)點(diǎn)開始向前遍歷直到
* 找到一個(gè)為非CANCELLED狀態(tài)的節(jié)點(diǎn)芬沉。
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
// 從尾節(jié)點(diǎn)向前遍歷到node節(jié)點(diǎn)之前找到非CANCELLED節(jié)點(diǎn)
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 如果遍歷后找到非CANCELLED狀態(tài)的節(jié)點(diǎn)則喚醒節(jié)點(diǎn)的線程
if (s != null)
LockSupport.unpark(s.thread);// 喚醒非CANCELLED狀態(tài)的線程
}
喚醒head后繼的有效節(jié)點(diǎn)图筹,如果head后繼節(jié)點(diǎn)為null或者為取消狀態(tài)钧唐,則從后向前遍歷找到第一個(gè)有效的節(jié)點(diǎn),被喚醒的節(jié)點(diǎn)會刪除前繼為取消狀態(tài)的節(jié)點(diǎn)(shouldParkAfterFailedAcquire()方法中),喚醒的節(jié)點(diǎn)加入對同步狀態(tài)的獲取中
注意:被喚醒的線程并不一定能獲得同步狀態(tài)
獨(dú)占式超時(shí)同步狀態(tài)獲取
隊(duì)列同步器AbstractQueuedSynchronizer源碼解析-續(xù)1
共享式同步狀態(tài)獲取與釋放
隊(duì)列同步器AbstractQueuedSynchronizer源碼解析-續(xù)2
同步隊(duì)列的使用方式
隊(duì)列同步器AbstractQueuedSynchronizer源碼解析-AQS使用
總結(jié)
從喚醒的線程競爭獲取同步狀態(tài)來看暖庄,AQS的獲取并非絕對公平的,因?yàn)槊恳粋€(gè)新增的節(jié)點(diǎn)獲取立馬競爭同步狀態(tài)灵寺,如果此時(shí)恰巧獲取成功則這種獲取是非公平的诫尽,失敗才會添加到等待隊(duì)列當(dāng)中,等待隊(duì)列內(nèi)部競爭才是FIFO的憔维,是公平的涛救。
如何做到公平獲取:需要tryAcquire和tryAcquireShared自定義方法中需要調(diào)用hasQueuedPredecessors方法來判斷等待隊(duì)列中是否含有不為當(dāng)前線程的head的后繼節(jié)點(diǎn)业扒,如果有检吆,則說明當(dāng)前線程并不能立馬去獲取同步狀態(tài),而是加入等待隊(duì)列中以FIFO來公平獲取同步狀態(tài)程储。
hasQueuedPredecessors方法hasQueuedPredecessors方法
重入公平鎖tryAcquire方法實(shí)例image.png
AQS中等待隊(duì)列的每個(gè)節(jié)點(diǎn)可以是獨(dú)占模式的也可以是共享模式的(即獨(dú)占模式和共享模式都共享自同一FIFO隊(duì)列)蹭沛,但是一般情況下臂寝,等待隊(duì)列中的所有節(jié)點(diǎn)的等待模式一般為同一種模式,比如ReentrantLock重入鎖摊灭,僅需重寫對應(yīng)的獲取和釋放的方法咆贬。也可以所有節(jié)點(diǎn)不為同一等待模式,如ReadWriteLock讀寫鎖斟或,需要重寫不同模式的獲取和釋放方法素征。
ConditionObject被定義為AQS內(nèi)部公共類,用來向外暴露給調(diào)用者萝挤;ConditionObject實(shí)現(xiàn)了Condition接口御毅,用于在獨(dú)占模式下。使用ConditionObject必須重寫isHeldExclusively方法怜珍,因?yàn)镃onditionObject多處調(diào)用了這個(gè)方法端蛆。ConditionObject詳解