當執行緒獲取不到鎖時,aqs使用自旋和阻塞;
為了支援取消和超時操作,aqs對clh鎖的佇列進行了改進,增加顯式的鏈結指向前繼節點。如果直接前繼節點取消或者超時了,就尋找直接前繼的前繼;
由於釋放鎖需要通知後繼節點,aqs又增加了後繼節點鏈結進行優化(非必要)。
乙個同步器一般需要包含以下兩個操作:
獲取操作:acquire
阻塞呼叫的執行緒,直到同步狀態允許其繼續執行。
while (同步狀態獲取失敗)
如果當前執行緒在佇列中,則移除
複製**
釋放操作:release
通過某種方式改變同步狀態,使得一或多個被acquire阻塞的執行緒繼續執行。
更新同步狀態
if (同步狀態許可乙個阻塞執行緒進行獲取)
複製**
因此我們可以從這兩個介面入手對原始碼進行解讀。另外需要補充說明的是,鎖的實現可以分為獨佔鎖和共享鎖,簡單起見,我們先聚焦獨享鎖的**實現,後續再看共享鎖的差異性。
acquire
public final void acquire(int arg)
複製**
嘗試獲取鎖,獲取成功直接返回,不執行後續操作;
建立代表當前執行緒的節點,加入等待佇列;
自旋前繼節點狀態和阻塞執行緒
tryacquire
該方法檢查同步狀態state
是否被許可,通俗來講就是看看是否能取到鎖。aqs中的實現只丟擲異常,所以基於aqs實現的鎖需要實現這個方法。
protected boolean tryacquire(int arg)
複製**
node
當同步狀態沒有被許可時,需要在等待佇列中排隊,因此需要建立乙個代表該執行緒的節點加入佇列。下面我們來看節點的定義(刪減了部分目前無須關注的屬性)。
static final class node
複製**
addwaiter
接下來需要把節點加入到等待佇列,整體思路是在隊尾插入節點。
入隊的時候需要考慮隊尾為空和不為空兩種情況,不過aqs的實現上是認為多數情況下隊尾都不為空,因此先按照隊尾不為空的方式嘗試快速入隊,如果失敗才用完整的入隊邏輯去入隊。
private node addwaiter(node mode)
}enq(node);
return node;
}複製**
enq
初始化佇列的頭節點和尾節點:
在隊尾插入新節點,addwaiter
中快速插入新節點的路徑就是這塊邏輯:
private node enq(final node node) else }}
}複製**
acquirequeued
節點加入佇列後,接下來要做的事就是不斷檢查狀態是否可用。這裡實現的思路是先看前繼節點是否是頭節點(因為只有頭節點釋放鎖後,後繼節點才有可能獲取到鎖),然後再去檢查狀態;如果前繼不是頭節點,則修改前繼節點的狀態waitstatus = signal
(表示後繼在等待喚醒),然後阻塞執行緒。
如果頭節點的後繼成功獲取到鎖了,則頭節點可以出隊了:
修改頭節點的指向到新節點(原頭節點的後繼);
新頭節點的前繼prev
置為null
(新頭節點的前繼就是原頭節點)
為了幫助gc**原頭節點,把原頭結點的後繼也置為null
。
final boolean acquirequeued(final node node, int arg)
if (shouldparkafte***iledacquire(p, node) &&
parkandcheckinterrupt())
interrupted = true;
}} finally
}複製**
接下來是釋放鎖的操作,從節點入隊的流程來看,釋放鎖時除了需要修改同步狀態status
,還需要喚醒後繼節點。
release
整個實現主要涉及下面三個事情:
public final boolean release(int arg)
return
false;
}複製**
unparksuccessor
unparksuccessor(h)
:
private void unparksuccessor(node node)
if (s != null)
locksupport.unpark(s.thread);
}複製**
《循序漸進學Spark》一第2章
第2章 spark 程式設計模型 與hadoop相比,spark最初為提公升效能而誕生。spark是hadoop mapreduce的演化和改進,並相容了一些資料庫的基本思想,可以說,spark一開始就站在hadoop與資料庫這兩個巨人的肩膀上。同時,spark依靠scala強大的函式式程式設計ac...
實現機器學習的循序漸進指南VI AdaBoost
目錄介紹 adaboost模型 弱分類器 權重更新 分類 結論與分析 可訪問 實現機器學習的循序漸進指南系列彙總,獲取本系列完成文章列表。adaboost 是boosting的一種方法,它基於多分類器組合可以在複雜環境中獲得更準確結果的原則。adaboost 模型由弱分類器,權重更新和分類組成。ad...
循序漸進的用js實現乙個bind
author thomaszhou 一般我們會直接使用bind函式,但是這次我們通過原生js來嘗試實現這個函式 bind 方法會建立乙個新函式。當這個新函式被呼叫時,bind 的第乙個引數將作為它執行時的 this,之後的一串行引數將會在傳遞的實參前傳入作為它的引數 由此我們可以首先得出 bind ...