先看鎖小結(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


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):

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

初始化
如果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ù)
