AQS 同步佇列共享模式

2021-08-21 21:25:59 字數 1981 閱讀 7762

首先來看看acquireshared()**,

public final void acquireshared(int arg)
tryacquireshared()方法同樣由自定義同步器實現,用來給state原子的加一些操作。如果tryacquireshared()<0說明當前執行緒嘗試獲取資源失敗需要進入同步佇列,來看看doacquireshared()**,

private void doacquireshared(int arg) 

}// 與獨享模式一樣,前乙個節點是signal時

// 進行park掛起當前執行緒等待喚醒

// 如果前乙個節點不是signal或者前乙個節點被取消

// 需要從尾部找到前乙個非null節點

// 最後將前乙個節點置為signal狀態並繼續執行for迴圈

if (shouldparkafte***iledacquire(p, node) &&

parkandcheckinterrupt())

interrupted = true;

}} finally

}

共享模式較之獨享模式的setheadandpropagate(),

private void setheadandpropagate(node node, int propagate) 

}

與獨享模式不一樣的是,當前節點獲取到資源後還會喚醒下乙個節點進行資源的獲取。

再來看看releaseshared()方法,

public final boolean releaseshared(int arg) 

return false;

}

首先嘗試釋放資源方法,如果前乙個或幾個執行緒已經釋放了共享資源(與獨享模式不一樣的是,獨享模式保證當state最初設定的值時才會喚醒下乙個節點),那麼tryreleaseshared()方法會返回true,然後執行doreleaseshared()方法喚醒下乙個節點,被喚醒的節點會嘗試tryacquireshared()方法。

private void doreleaseshared() 

else if (ws == 0 &&

!compareandsetwaitstatus(h, 0, node.propagate))

continue;

}// 如果喚醒的後繼節點獲取到資源將頭節點改變

// 退出迴圈

if (h == head)

break;}}

假定我們有10個資源,a執行緒正在占用7個,b執行緒正在占用2個,剩餘1個資源

這時c執行緒需要獲取資源,但是需要4個資源才能繼續執行,所以c執行緒到來時初始化同步佇列並將c執行緒加入到同步佇列

此時a執行緒釋放掉乙個資源,喚醒頭節點的下乙個節點嘗試資源的獲取,此時共有2個資源可以獲取,所以c獲取資源失敗

同時又來了乙個執行緒d嘗試獲取資源,d需要3個資源才能繼續執行,d加入同步佇列進行掛起等待資源獲取

此時a再次釋放了乙個資源,喚醒頭節點下乙個節點,失敗(注意!!!這裡體現共享鎖的公平性與非公平性,a再次釋放資源後空閒3個資源,而d正好需要3個資源就可以繼續執行,如果是公平的共享鎖則只會按照佇列順序進行排隊獲取資源;如果是非共享鎖,則d此時可以獲取資源進行下一步操作)

a再次釋放2個資源,b釋放2個資源,嘗試喚醒c,成功,並且c成為頭節點後再次喚醒d也成功(體現共享的一步),頭節點執行的節點是獲取到資源的節點

同步器AQS中的同步佇列與等待佇列

在單純地使用鎖,比如reentrantlock的時候,這個鎖元件內部有乙個繼承同步器aqs的類,實現了其抽象方法,加鎖 釋放鎖也只是涉及到aqs中的同步佇列而已,那麼等待佇列又是什麼呢?當使用condition的時候,等待佇列的概念就出來了。condition的獲取一般都要與乙個鎖lock相關,乙個...

CLH同步佇列

aqs內部維護著乙個fifo佇列,該佇列就是clh同步佇列。clh同步佇列是乙個fifo雙向佇列,aqs依賴它來完成同步狀態的管理,當前執行緒如果獲取同步狀態失敗時,aqs則會將當前執行緒已經等待狀態等資訊構造成乙個節點 node 並將其加入到clh同步佇列,同時會阻塞當前執行緒,當同步狀態釋放時,...

執行緒程式設計 同步佇列

我們經常會採用生產者 消費者關係的兩個執行緒來處理乙個共享緩衝區的資料。例如一 個生產者執行緒接受使用者資料放入乙個共享緩衝區裡,等待乙個消費者執行緒對資料取出處理。但是如果緩衝區的太小而生產者和消費者兩個非同步執行緒的速度不同時,容 易出現乙個執行緒等待另乙個情況。為了盡可能的縮短共享資源並以相同...