面試總結(jié)——并發(fā)

先看鎖小結(jié)Synchronized基礎(chǔ)以及Volatile基礎(chǔ)極客時(shí)間,再結(jié)合練習(xí)題擴(kuò)展復(fù)習(xí)

1.Nio,AIO,BIO

https://segmentfault.com/a/1190000012316621
https://tech.meituan.com/nio.html
file:///C:/Users/wang/Desktop/%E6%A0%A1%E6%8B%9B/java%E9%9D%A2%E7%BB%8F%E6%80%BB%E7%BB%93%EF%BC%88%E5%B8%A6%E7%AD%94%E6%A1%88%EF%BC%89.pdf
https://time.geekbang.org/column/article/8369

image.png

image.png

2.future

https://www.cnblogs.com/cz123/p/7693064.html
https://blog.csdn.net/ghsau/article/details/7451464

3.AQS和ReentrantLock相關(guān)

1.http://www.itdecent.cn/p/ac0fb814e1a3
2.http://www.itdecent.cn/p/d2f5efc0f51a
3.https://wwwjianshu.com/p/3b5ea60c5ad9
4.http://www.itdecent.cn/p/508412a6ffdc
5.并發(fā)包中常見(jiàn)的工具類
在AQS中維護(hù)著一個(gè)FIFO的同步隊(duì)列,當(dāng)線程獲取同步狀態(tài)失敗后,則會(huì)加入到這個(gè)CLH同步隊(duì)列的對(duì)尾并一直保持著自旋。在CLH同步隊(duì)列中的線程在自旋時(shí)會(huì)判斷其前驅(qū)節(jié)點(diǎn)是否為首節(jié)點(diǎn),如果為首節(jié)點(diǎn)則不斷嘗試獲取同步狀態(tài),獲取成功則退出CLH同步隊(duì)列。當(dāng)線程執(zhí)行完邏輯后,會(huì)釋放同步狀態(tài),釋放后會(huì)喚醒其后繼節(jié)點(diǎn)。

一個(gè)可重入的互斥鎖定 Lock,它具有與使用 synchronized 方法和語(yǔ)句所訪問(wèn)的隱式監(jiān)視器鎖定相同的一些基本行為和語(yǔ)義,但功能更強(qiáng)大。ReentrantLock 將由最近成功獲得鎖定,并且還沒(méi)有釋放該鎖定的線程所擁有。當(dāng)鎖定沒(méi)有被另一個(gè)線程所擁有時(shí),調(diào)用 lock 的線程將成功獲取該鎖定并返回。如果當(dāng)前線程已經(jīng)擁有該鎖定,此方法將立即返回??梢允褂?isHeldByCurrentThread() 和 getHoldCount() 方法來(lái)檢查此情況是否發(fā)生。

4.ConcurrentHashMap的原理:

ConcurrentHashMap采用 分段鎖的機(jī)制,實(shí)現(xiàn)并發(fā)的更新操作,底層采用數(shù)組+鏈表的存儲(chǔ)結(jié)構(gòu)。
其包含兩個(gè)核心靜態(tài)內(nèi)部類 Segment和HashEntry。

Segment繼承ReentrantLock用來(lái)充當(dāng)鎖的角色,每個(gè) Segment 對(duì)象守護(hù)每個(gè)散列映射表的若干個(gè)桶。
HashEntry 用來(lái)封裝映射表的鍵 / 值對(duì);
每個(gè)桶是由若干個(gè) HashEntry 對(duì)象鏈接起來(lái)的鏈表。
一個(gè) ConcurrentHashMap 實(shí)例中包含由若干個(gè) Segment 對(duì)象組成的數(shù)組,下面我們通過(guò)一個(gè)圖來(lái)演示一下 ConcurrentHashMap 的結(jié)構(gòu):


image.png

1.8的實(shí)現(xiàn)已經(jīng)拋棄了Segment分段鎖機(jī)制,利用CAS+Synchronized來(lái)保證并發(fā)更新的安全,底層采用數(shù)組+鏈表+紅黑樹(shù)的存儲(chǔ)結(jié)構(gòu)。


image.png
初始化

如果sizeCtl為負(fù)數(shù),則說(shuō)明已經(jīng)有其它線程正在進(jìn)行擴(kuò)容,即正在初始化或初始化完成。這樣的話就暫停當(dāng)前線程。如果CAS成功,則表示正在初始化,設(shè)置為 -1,否則說(shuō)明其它線程已經(jīng)對(duì)其正在初始化或是已經(jīng)初始化完畢

put的步驟
  • 檢查key/value是否為空,如果為空,則拋異常,否則進(jìn)行2
  • 進(jìn)入for死循環(huán),進(jìn)行3
  • 檢查table是否初始化了,如果沒(méi)有,則調(diào)用initTable()進(jìn)行初始化然后進(jìn)行 2,否則進(jìn)行4
  • 根據(jù)key的hash值計(jì)算出其應(yīng)該在table中儲(chǔ)存的位置i,取出table[i]的節(jié)點(diǎn)用f表示。
    根據(jù)f的不同有如下三種情況:
    1)如果table[i]==null(即該位置的節(jié)點(diǎn)為空,沒(méi)有發(fā)生碰撞),
    則利用CAS操作直接存儲(chǔ)在該位置,如果CAS操作成功則退出死循環(huán)。
    2)如果table[i]!=null(即該位置已經(jīng)有其它節(jié)點(diǎn),發(fā)生碰撞),碰撞處理也有兩種情況
    2.1)檢查table[i]的節(jié)點(diǎn)的hash是否等于MOVED,如果等于,則檢測(cè)到正在擴(kuò)容,則幫助其擴(kuò)容
    2.2)說(shuō)明table[i]的節(jié)點(diǎn)的hash值不等于MOVED,如果table[i]為鏈表節(jié)點(diǎn),則將此節(jié)點(diǎn)插入鏈表中即可
    如果table[i]為樹(shù)節(jié)點(diǎn),則將此節(jié)點(diǎn)插入樹(shù)中即可。插入成功后,進(jìn)行 5
  • 如果table[i]的節(jié)點(diǎn)是鏈表節(jié)點(diǎn),則檢查table的第i個(gè)位置的鏈表是否需要轉(zhuǎn)化為樹(shù),如果需要?jiǎng)t調(diào)用treeifyBin函數(shù)進(jìn)行轉(zhuǎn)化
get的步驟
  • 根據(jù)key調(diào)用spread計(jì)算hash值;并根據(jù)計(jì)算出來(lái)的hash值計(jì)算出該key在table出現(xiàn)的位置i.
  • 檢查table是否為空;如果為空,返回null,否則進(jìn)行3
  • 檢查table[i]處桶位不為空;如果為空,則返回null,否則進(jìn)行4
  • 先檢查table[i]的頭結(jié)點(diǎn)的key是否滿足條件,是則返回頭結(jié)點(diǎn)的value;否則分別根據(jù)樹(shù)、鏈表查詢。

get方法的思想是不是也很簡(jiǎn)單哈,與HashMap的get方法一模一樣,分析到這里,ConcurrentHashMap類的源碼的大概實(shí)現(xiàn)思路我們就基本清晰了哈,本著學(xué)習(xí)的精神,我們還是稍微看下其他的方法哈,例如:containsKey、remove、size等等

5.CAS函數(shù)
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容