慕課網(wǎng)高并發(fā)實(shí)戰(zhàn)(七)- J.U.C之AQS

7.1? AbstractQueuedSynchronizer -AQS

底層實(shí)現(xiàn)了雙向鏈表削罩,是隊(duì)列的一種實(shí)現(xiàn)方式

對(duì)象創(chuàng)建以后其狀態(tài)就不能修改




底層是雙向鏈表,隊(duì)列的一種實(shí)現(xiàn)

sync queue:同步隊(duì)列糊昙,head節(jié)點(diǎn)主要負(fù)責(zé)后面的調(diào)度

Condition queue:單向鏈表辛掠,不是必須的的,也可以有多個(gè)

設(shè)計(jì)原理

使用Node實(shí)現(xiàn)FIFO隊(duì)列,可以用于構(gòu)建鎖或者其他同步裝置的基礎(chǔ)框架

利用了一個(gè)int類型標(biāo)示狀態(tài)萝衩,有一個(gè)state的成員變量回挽,表示獲取鎖的線程數(shù)(0沒有線程獲取鎖,1有線程獲取鎖猩谊,大于1表示重入鎖的數(shù)量)千劈,和一個(gè)同步組件ReentrantLock,

使用方法是繼承牌捷,基于模板方法

子類通過繼承并通過實(shí)現(xiàn)它的方法管理其狀態(tài){acquire和release}的方法操作狀態(tài)

可以實(shí)現(xiàn)排它鎖和共享鎖的模式(獨(dú)占墙牌、共享,子類只能實(shí)現(xiàn)其中一個(gè))

具體實(shí)現(xiàn)的思路

1.首先 AQS內(nèi)部維護(hù)了一個(gè)CLH隊(duì)列暗甥,來管理鎖

線程嘗試獲取鎖喜滨,如果獲取失敗,則將等待信息等包裝成一個(gè)Node結(jié)點(diǎn)撤防,加入到同步隊(duì)列Sync queue里

3.不斷重新嘗試獲取鎖(當(dāng)前結(jié)點(diǎn)為head的直接后繼才會(huì) 嘗試)虽风,如果獲取失敗,則會(huì)阻塞自己寄月,直到被喚醒

4.當(dāng)持有鎖的線程釋放鎖的時(shí)候辜膝,會(huì)喚醒隊(duì)列中的后繼線程

AQS同步組件

CountDownLatch(閉鎖,通過一個(gè)計(jì)數(shù)保證線程是否需要一直阻塞 )

Semaphore(控制同一時(shí)間并發(fā)線程的數(shù)目)

CyclicBarrier(與CountDownLatch 相識(shí) 阻塞線程剥懒,可以重置計(jì)數(shù)器)

ReentrantLock

Condition

FutureTask

CountDownLatch

同步阻塞類内舟,可以完成阻塞線程的功能








*&&&& CountDownLatch :閉鎖,通過一個(gè)計(jì)數(shù)初橘,判斷線程是否阻塞

&&&&? Semaphore:控制并發(fā)線程的數(shù)目


7.2??CountDownLatch?

同步輔組類验游,完成阻塞當(dāng)前線程的功能,給定了一個(gè)計(jì)數(shù)器保檐,原子操作耕蝉,計(jì)數(shù)器不能重置。

調(diào)用await()方法會(huì)使線程處于阻塞狀態(tài)夜只,直到其他線程調(diào)用CountDown()方法時(shí)垒在,才繼續(xù)執(zhí)行

當(dāng)計(jì)數(shù)器變?yōu)?的時(shí)候,所有等待的線程才會(huì)繼續(xù)執(zhí)行

使用場景:查詢需要等待某個(gè)條件完成后才能繼續(xù)執(zhí)行后續(xù)操作(Ex:并行計(jì)算)拆分任務(wù)



7.3 Semaphore


并發(fā)訪問控制線程個(gè)數(shù)(同步機(jī)制)扔亥,? ?提供了兩個(gè)方法场躯,實(shí)現(xiàn)有限大小的鏈表大小

semaphore.acquire(); // 獲取一個(gè)許可

semaphore.release(); // 釋放一個(gè)許可

semaphore.acquire(n);//獲取多個(gè)許可

semaphore.release(n); // 釋放n個(gè)許可


使用場景:僅能提供有限訪問的資源,比如數(shù)據(jù)庫連接數(shù)


tryAcquire())//嘗試獲取一個(gè)許可


tryAcquire 四個(gè)帶參方法

?1 tryAcquire(long timeout, TimeUnit unit)

?2??tryAcquire()

3??tryAcquire(int permits)

4??boolean tryAcquire(int permits, long timeout, TimeUnit unit)


7.4? CyclicBarrier



運(yùn)行一組線程等待到一個(gè)公共的屏障點(diǎn)旅挤,實(shí)現(xiàn)多個(gè)線程相互等待踢关,當(dāng)每一個(gè)線程都就緒后,才執(zhí)行下去,通過計(jì)數(shù)器實(shí)現(xiàn)的

多線程計(jì)算數(shù)據(jù),最后合并的場景


CyclicBarrier 與CountDownLatch 的區(qū)別

1??CountDownLatch 的計(jì)數(shù)器只能使用一次,CyclicBarrier 可以使用reset()方法重置

2?CountDownLatch 實(shí)現(xiàn)一個(gè)或者n個(gè)線程需要等待其他線程執(zhí)行某項(xiàng)操作后才能繼續(xù)執(zhí)行?

?CyclicBarrier? 實(shí)現(xiàn)多個(gè)線程了多個(gè)線程相互等待诱告,知道多個(gè)線程都滿足了某個(gè)條件以后才繼續(xù)執(zhí)行

描述的多個(gè)線程內(nèi)部的關(guān)系儒搭,多個(gè)線程都調(diào)用await()方法后才繼續(xù)向下執(zhí)行

提供方法獲取阻塞線程的個(gè)數(shù)吠架,知道阻塞的線程是否中斷

CyclicBarrier? 對(duì)象調(diào)用await() 等待多個(gè)線程都滿足條件后,在往下面執(zhí)行


//定義有5個(gè)線程同步等待

1) private static CyclicBarrierbarrier =new CyclicBarrier(5);

2 )

在5個(gè)線程都滿足條件后搂鲫,先執(zhí)行?log.info("callback is running"); 在執(zhí)行以后的代碼

private static CyclicBarrierbarrier =new CyclicBarrier(5, () -> {

log.info("callback is running");

});



7.5 ReentrantLock 與鎖


java? 兩類鎖: 1?synchronized?

? ? ? ? ? ? ? ? ? ? ? ?2 JUC的 ReentrantLock?


?ReentrantLock 與synchronized 的區(qū)別

1 &&&? 可重入性 兩者都是可重入鎖 傍药,同一線程進(jìn)入一次 鎖的計(jì)數(shù)器就自增1 ,鎖的計(jì)數(shù)器下降為0 時(shí)才釋放鎖

2 &&&? synchronized 是依賴jvm實(shí)現(xiàn)的(操作系統(tǒng)實(shí)現(xiàn)魂仍,難查源碼)怔檩,ReentrantLock 是依賴jdk實(shí)現(xiàn)的(用戶實(shí)現(xiàn))

3 &&&? 兩者性能差不多 ,推薦使用synchronized 蓄诽,synchronized 優(yōu)化借鑒了CAS技術(shù)薛训,用戶態(tài)解決加鎖問題避免進(jìn)入內(nèi)核態(tài) 使線程阻塞

4 &&&? synchronized? 更方便它是編譯器保證鎖的加鎖和釋放的,ReentrantLock 手工釋放和加鎖仑氛,在finally釋放鎖

鎖的細(xì)膩度和靈活度?ReentrantLock 更好?

ReentrantLock? 的獨(dú)有的功能

1? ReentrantLock?可指定是公平鎖和非公平鎖??synchronized 只能是非公平鎖

公平鎖(先等待的線程先獲得鎖)

2 提供了一個(gè)Condition類乙埃,可以分組喚醒需要喚醒的線程

synchronized? 喚醒一個(gè)要不全部喚醒

3? 提供能夠中斷等待鎖的線程的機(jī)制,lock.lockInterruptibly()

ReentrantLock 實(shí)現(xiàn)是一種自旋鎖锯岖,通過循環(huán)調(diào)用cas操作自加操作介袜,避免了線程進(jìn)入內(nèi)核態(tài)發(fā)生阻塞?

synchronized 不會(huì)忘記釋放鎖

ReentrantLock 函數(shù)方法

tryLock():僅在調(diào)用時(shí)鎖定未被另外一個(gè)線程保持的情況下獲取鎖定

tryLock(long timeout, TimeUnit unit) 如果鎖定在給定的時(shí)間內(nèi)沒有被另一個(gè)線程保持,且當(dāng)前線程沒有被中斷出吹,則獲取這個(gè)鎖定

lockInterruptibly() 當(dāng)前線程如果沒有中斷就獲取鎖定遇伞,如果已經(jīng)中斷就拋出異常

isLocked() 查詢當(dāng)前此鎖定是否由任意線程保持,


ReentrantReadWriteLock? ?

?在沒有任何 讀寫鎖(ReadWrite)*的情況下才能取得寫鎖(Write)


StampedLock?

版本和模式兩個(gè)部分組成

控制鎖的三種方式:

1 寫

2 讀

3 樂觀讀

鎖獲取的方法是一個(gè)數(shù)字捶牢,用鎖的狀態(tài)控制相關(guān)鎖的狀態(tài)的訪問

數(shù)字0 表示沒有寫鎖

讀鎖分為 悲觀鎖 和樂觀鎖

對(duì)吞吐量有巨大的改進(jìn)鸠珠,特別是讀線程多的場景中下

StampedLock? 對(duì)于加鎖容易誤用其他的方法


Condition?


package com.mmall.concurrency.example.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j

public class LockExample6 {

public static void main(String[] args) {

ReentrantLock reentrantLock =new ReentrantLock();

? ? ? ? Condition condition = reentrantLock.newCondition();

? ? ? ? new Thread(() -> {

try {

reentrantLock.lock(); // 線程加入到AQS的等待隊(duì)列中

? ? ? ? ? ? ? ? log.info("wait signal"); // 1

? ? ? ? ? ? ? ? condition.await(); //調(diào)用await()方法后 線程從AQS對(duì)列中溢出(鎖的釋放),進(jìn)入到condition的等待隊(duì)列中

? ? ? ? ? ? }catch (InterruptedException e) {

e.printStackTrace();

? ? ? ? ? ? }

log.info("get signal"); // 4

? ? ? ? ? ? reentrantLock.unlock();

? ? ? ? }).start();

? ? ? ? new Thread(() -> {

reentrantLock.lock();

? ? ? ? ? ? log.info("get lock"); // 2

? ? ? ? ? ? try {

Thread.sleep(3000);

? ? ? ? ? ? }catch (InterruptedException e) {

e.printStackTrace();

? ? ? ? ? ? }

condition.signalAll();

? ? ? ? ? ? log.info("send signal ~ "); // 3

? ? ? ? ? ? reentrantLock.unlock();

? ? ? ? }).start();

? ? }

}

result:

- wait signal

- get lock

- send signal ~

- get signal




總結(jié)

1 只有少量競爭者的時(shí)候秋麸,synchronized是比較好的選擇?

2 競爭者不少渐排,線程的數(shù)量可以預(yù)估的,ReentrantLock 是一個(gè)比較好的鎖實(shí)現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末灸蟆,一起剝皮案震驚了整個(gè)濱河市驯耻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炒考,老刑警劉巖可缚,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斋枢,居然都是意外死亡帘靡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門杏慰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來测柠,“玉大人,你說我怎么就攤上這事缘滥『湫玻” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵朝扼,是天一觀的道長赃阀。 經(jīng)常有香客問我,道長擎颖,這世上最難降的妖魔是什么榛斯? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮搂捧,結(jié)果婚禮上驮俗,老公的妹妹穿的比我還像新娘。我一直安慰自己允跑,他們只是感情好王凑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著聋丝,像睡著了一般索烹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弱睦,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天百姓,我揣著相機(jī)與錄音,去河邊找鬼况木。 笑死垒拢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的火惊。 我是一名探鬼主播子库,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼矗晃!你這毒婦竟也來了仑嗅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤张症,失蹤者是張志新(化名)和其女友劉穎仓技,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俗他,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脖捻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兆衅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片地沮。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗜浮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出摩疑,到底是詐尸還是另有隱情危融,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布雷袋,位于F島的核電站吉殃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏楷怒。R本人自食惡果不足惜蛋勺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸠删。 院中可真熱鬧抱完,春花似錦、人聲如沸刃泡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捅僵。三九已至家卖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庙楚,已是汗流浹背上荡。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留馒闷,地道東北人酪捡。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像纳账,于是被迫代替她去往敵國和親逛薇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Java并發(fā)總結(jié) 1.多線程的優(yōu)點(diǎn) 資源利用率更好 程序在某些情況下更簡單 程序響應(yīng)更快 2.創(chuàng)建線程 1.實(shí)現(xiàn)R...
    不會(huì)上樹的猴子閱讀 1,018評(píng)論 0 5
  • 1.明明就已經(jīng)一大把年紀(jì)呢袱,卻還是渴望童話世界,把自己當(dāng)成公主翅敌,期待白馬王子的出現(xiàn)羞福。 2.明明才二十多歲,就開始每天...
    愛吃肉肉的小蜻蜓閱讀 192評(píng)論 0 0
  • 關(guān)于AndroidAsync AndroidAsync封裝了常用的異步請(qǐng)求比如獲取字符串蚯涮、獲取JSON治专、獲取文件等...
    黃海佳閱讀 8,142評(píng)論 0 3
  • 2017高考作文詩歌 我拿著單反卖陵,騎著共享單車 今天是高考四十年,我的 高考在汽車火車自行車 的一帶一路上預(yù)測 那...
    冰眉鐵面閱讀 377評(píng)論 0 3