java 集合類繁成,ConcurrentHashMap詳解

HashMap 1.8 put get過程:

HashMap? ConcurrentHashMap? 相信看完這篇沒人能難住你焚辅!

  • put:
    1凄贩、判斷當(dāng)前桶是否為空,空的就需要初始化(resize 中會判斷是否進行初始化)袱讹。
    2疲扎、根據(jù)當(dāng)前 key 的 hashcode 定位到具體的桶中并判斷是否為空,為空表明沒有 Hash 沖突就直接在當(dāng)前位置創(chuàng)建一個新桶即可捷雕。
    3椒丧、如果當(dāng)前桶有值( Hash 沖突),那么就要比較當(dāng)前桶中的 key救巷、key 的 hashcode 與寫入的 key 是否相等壶熏,相等就賦值給 e,在第 8 步的時候會統(tǒng)一進行賦值及返回。
    4浦译、如果當(dāng)前桶為紅黑樹棒假,那就要按照紅黑樹的方式寫入數(shù)據(jù)。
    5精盅、如果是個鏈表帽哑,就需要將當(dāng)前的 key、value 封裝成一個新節(jié)點寫入到當(dāng)前桶的后面(形成鏈表)叹俏。
    6妻枕、接著判斷當(dāng)前鏈表的大小是否大于預(yù)設(shè)的閾值,大于時就要轉(zhuǎn)換為紅黑樹。
    7屡谐、如果在遍歷過程中找到 key 相同時直接退出遍歷述么。
    8、如果 e != null 就相當(dāng)于存在相同的 key,那就需要將值覆蓋愕掏。
    9度秘、最后判斷是否需要進行擴容。

  • get:
    1亭珍、首先將 key hash 之后取得所定位的桶敷钾。
    2、如果桶為空則直接返回 null 肄梨。
    3阻荒、否則判斷桶的第一個位置(有可能是鏈表、紅黑樹)的 key 是否為查詢的 key众羡,是就直接返回 value侨赡。
    4、如果第一個不匹配粱侣,則判斷它的下一個是紅黑樹還是鏈表羊壹。
    5、紅黑樹就按照樹的查找方式返回值齐婴。
    6油猫、不然就按照鏈表的方式遍歷匹配返回值。

HashMap為啥線程不安全

為什么HashMap線程不安全 -- 很棒

1柠偶、 put的時候情妖,hash沖突會導(dǎo)致數(shù)據(jù)被覆蓋而丟失(一直存在
2、 多線程Resize時可能會形成環(huán)形鏈表诱担,當(dāng)執(zhí)行 get 時毡证,當(dāng)key 正好被分到那個 table[i] 上時,遍歷鏈表就會產(chǎn)生循環(huán)蔫仙。(jdk1.8用紅黑樹修復(fù)

  • JDK8的修復(fù):
    JDK8 將 HashMap 的結(jié)構(gòu)作了修改料睛,將原來的鏈表部分改為數(shù)據(jù)少時仍然鏈表,當(dāng)超過一定數(shù)量后變換為紅黑樹摇邦。
    HashMap在jdk1.7中采用頭插入法恤煞,在擴容時會改變鏈表中元素原本的順序,以至于在并發(fā)場景下導(dǎo)致鏈表成環(huán)的問題施籍。而在jdk1.8中采用尾插入法阱州,在擴容時會保持鏈表元素原本的順序,就不會出現(xiàn)鏈表成環(huán)的問題了法梯。
    HashMap 多線程下死循環(huán)分析及JDK8修復(fù)

  • HashMap在1.7和1.8之間的變化:
    1苔货、1.7采用數(shù)組+單鏈表犀概,1.8在單鏈表超過一定長度后改成紅黑樹存儲
    2、1.7擴容時需要重新計算哈希值和索引位置夜惭,1.8并不重新計算哈希值姻灶,巧妙地采用和擴容后容量進行&操作來計算新的索引位置。
    3诈茧、1.7插入元素到單鏈表中采用頭插入法产喉,1.8采用的是尾插入法。

ConcurrentHashMap原理

  • JDK1.7分析:

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

  1. Segment繼承ReentrantLock用來充當(dāng)鎖的角色塞俱,每個 Segment 對象守護每個散列映射表的若干個桶。
  2. HashEntry 用來封裝映射表的鍵 / 值對吏垮;
  3. 每個桶是由若干個 HashEntry 對象鏈接起來的鏈表障涯。

一個 ConcurrentHashMap 實例中包含由若干個 Segment 對象組成的數(shù)組,下面我們通過一個圖來演示一下 ConcurrentHashMap 的結(jié)構(gòu):

  • JDK1.8分析:

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

image

Segment+ReentrantLock VS CAS+Synchronized
ConcurrentHashMap 1.8為什么要使用CAS+Synchronized取代Segment+ReentrantLock

1.7:

  • 在初始化ConcurrentHashMap的時候,會初始化一個Segment數(shù)組,容量為16,而每個Segment呢,都繼承了ReentrantLock類,也就是說每個Segment類本身就是一個鎖,之后Segment內(nèi)部又有一個table數(shù)組,而每個table數(shù)組里的索引數(shù)據(jù)呢,又對應(yīng)著一個Node鏈表遗嗽。
  • 使用put方法的時候,是對我們的key進行hash拿到一個整型,然后將整型對16取模,拿到對應(yīng)的Segment,之后調(diào)用Segment的put方法,然后上鎖,請注意,這里lock()的時候其實是this.lock(),也就是說,每個Segment的鎖是分開的粘我。

1.8:
Synchronized上鎖的對象,請記住,Synchronized是靠對象的對象頭和此對象對應(yīng)的monitor來保證上鎖的,也就是對象頭里的重量級鎖標(biāo)志指向了monitor,而monitor呢,內(nèi)部則保存了一個當(dāng)前線程,也就是搶到了鎖的線程.

那么這里的這個f是什么呢?f一定是鏈表的頭結(jié)點,即該元素在Node數(shù)組中征字。所以這里鎖住的是hash沖突那條鏈表。

它是Node鏈表里的每一個Node,也就是說,Synchronized是將每一個Node對象作為了一個鎖,這樣做的好處是什么呢?將鎖細(xì)化了,也就是說,除非兩個線程同時操作一個Node,注意,是一個Node而不是一個Node鏈表哦,那么才會爭搶同一把鎖晴音。

如果使用ReentrantLock其實也可以將鎖細(xì)化成這樣的,只要讓Node類繼承ReentrantLock就行了,這樣的話調(diào)用f.lock()就能做到和Synchronized(f)同樣的效果,但為什么不這樣做呢?

請大家試想一下,鎖已經(jīng)被細(xì)化到這種程度了,那么出現(xiàn)并發(fā)爭搶的可能性還高嗎?還有就是,哪怕出現(xiàn)爭搶了,只要線程可以在30到50次自旋里拿到鎖,那么Synchronized就不會升級為重量級鎖,而等待的線程也就不用被掛起,我們也就少了掛起和喚醒這個上下文切換的過程開銷.

但如果是ReentrantLock呢?它則只有在線程沒有搶到鎖,然后新建Node節(jié)點后再嘗試一次而已,不會自旋,而是直接被掛起,這樣一來,我們就很容易會多出線程上下文開銷的代價.當(dāng)然,你也可以使用tryLock(),但是這樣又出現(xiàn)了一個問題,你怎么知道tryLock的時間呢?在時間范圍里還好,假如超過了呢?

所以,在鎖被細(xì)化到如此程度上,使用Synchronized是最好的選擇了.這里再補充一句,Synchronized和ReentrantLock他們的開銷差距是在釋放鎖時喚醒線程的數(shù)量,Synchronized是喚醒鎖池里所有的線程+剛好來訪問的線程,而ReentrantLock則是當(dāng)前線程后進來的第一個線程+剛好來訪問的線程.

如果是線程并發(fā)量不大的情況下,那么Synchronized因為自旋鎖,偏向鎖,輕量級鎖的原因,不用將等待線程掛起,偏向鎖甚至不用自旋,所以在這種情況下要比ReentrantLock高效

集合類

JAVA集合類
Java提高篇(三四)-----fail-fast機制

函數(shù)式編程锤躁,stream用法,Lambda表達(dá)式

Java 8 函數(shù)式接口
JDK 8 函數(shù)式編程入門
Java 8 中的 Streams API 詳解

  • “快速失敗”也就是fail-fast
  • 它是Java集合的一種錯誤檢測機制梧乘。當(dāng)多個線程對集合進行結(jié)構(gòu)上的改變的操作時填渠,有可能會產(chǎn)生fail-fast機制氛什。記住是有可能,而不是一定饺饭。例如:假設(shè)存在兩個線程(線程1鹊杖、線程2),線程1通過Iterator在遍歷集合A中的元素登下,在某個時候線程2修改了集合A的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改畔濒,而不是簡單的修改集合元素的內(nèi)容),那么這個時候程序就會拋出 ConcurrentModificationException 異常妇菱,從而產(chǎn)生fail-fast機制房交。
  • 這一策略在源碼中的實現(xiàn)是通過 modCount 域白群,modCount 顧名思義就是修改次數(shù)唯卖,對 HashMap 內(nèi)容(當(dāng)然不僅僅是 HashMap 才會有卵沉,其他例如 ArrayList 也會)的修改都將增加這個值(大家可以再回頭看一下其源碼,在很多操作中都有 modCount++ 這句)堪嫂,那么在迭代器初始化過程中會將這個值賦給迭代器的 expectedModCount偎箫。
  • 解決方案
    在上文中也提到木柬,fail-fast 機制皆串,是一種錯誤檢測機制。它只能被用來檢測錯誤眉枕,因為 JDK 并不保證 fail-fast 機制一定會發(fā)生恶复。若在多線程環(huán)境下使用 fail-fast 機制的集合怜森,建議使用“java.util.concurrent 包下的類”去取代“java.util 包下的類”。
  • java集合框架圖

Map:

  • LinkedHashMap 幾乎和 HashMap 一樣:從技術(shù)上來說谤牡,不同的是它定義了一個 Entry<K,V> header副硅,這個 header 不是放在 Table 里,它是額外獨立出來的翅萤。LinkedHashMap 通過繼承 hashMap 中的 Entry<K,V>,并添加兩個屬性 Entry<K,V> before,after,和 header 結(jié)合起來組成一個雙向鏈表恐疲,來實現(xiàn)按插入順序或訪問順序排序。

  • Hashtable 與 HashMap 的簡單比較

  • 1套么、HashTable 基于 Dictionary 類培己,而 HashMap 是基于 AbstractMap。Dictionary 是任何可將鍵映射到相應(yīng)值的類的抽象父類胚泌,而 AbstractMap 是基于 Map 接口的實現(xiàn)省咨,它以最大限度地減少實現(xiàn)此接口所需的工作。
  • 2玷室、HashMap 的 key 和 value 都允許為 null零蓉,而 Hashtable 的 key 和 value 都不允許為 null。HashMap 遇到 key 為 null 的時候穷缤,調(diào)用 putForNullKey 方法進行處理敌蜂,而對 value 沒有處理;Hashtable遇到 null绅项,直接返回 NullPointerException紊册。
  • 3、Hashtable 方法是同步快耿,而HashMap則不是囊陡。我們可以看一下源碼,Hashtable 中的幾乎所有的 public 的方法都是 synchronized 的掀亥,而有些方法也是在內(nèi)部通過 synchronized 代碼塊來實現(xiàn)撞反。所以有人一般都建議如果是涉及到多線程同步時采用 HashTable,沒有涉及就采用 HashMap搪花,但是在 Collections 類中存在一個靜態(tài)方法:synchronizedMap()遏片,該方法創(chuàng)建了一個線程安全的 Map 對象,并把它作為一個封裝的對象來返回

Java HashMap源碼分析

深入淺出ConcurrentHashMap1.8

ConcurrentHashMap 的實現(xiàn)原理

主題:ConcurrentHashMap之實現(xiàn)細(xì)節(jié)

HashMap為什么線程不安全(hash碰撞與擴容導(dǎo)致)

圖解集合5:不正確地使用HashMap引發(fā)死循環(huán)及元素丟失

淺析HashMap與ConcurrentHashMap的線程安全性

java集合類TreeMap和TreeSet

Java集合類及并發(fā)集合類

  • map結(jié)構(gòu)圖

  • map比較

  • map比較1

List:

Arrays.asList使用指南
使用java.util.List.subList時最好小心點

  • List架構(gòu)

  • List比較

  • List比較1

Set:

  • HashSet撮竿,它是基于 HashMap 實現(xiàn)的吮便,底層采用 HashMap 來保存元素,對于 HashSet 中保存的對象,請注意正確重寫其 equals 和 hashCode 方法幢踏,以保證放入的對象的唯一性髓需。

  • LinkedHashSet 是 Set 的一個具體實現(xiàn),其維護著一個運行于所有條目的雙重鏈接列表房蝉。此鏈接列表定義了迭代順序僚匆,該迭代順序可為插入順序或是訪問順序微渠。

Vector

Stack

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市咧擂,隨后出現(xiàn)的幾起案子逞盆,更是在濱河造成了極大的恐慌,老刑警劉巖松申,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件云芦,死亡現(xiàn)場離奇詭異,居然都是意外死亡贸桶,警方通過查閱死者的電腦和手機焕数,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刨啸,“玉大人堡赔,你說我怎么就攤上這事∩枇” “怎么了善已?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長离例。 經(jīng)常有香客問我换团,道長,這世上最難降的妖魔是什么宫蛆? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任艘包,我火速辦了婚禮,結(jié)果婚禮上耀盗,老公的妹妹穿的比我還像新娘想虎。我一直安慰自己,他們只是感情好叛拷,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布舌厨。 她就那樣靜靜地躺著,像睡著了一般忿薇。 火紅的嫁衣襯著肌膚如雪裙椭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天署浩,我揣著相機與錄音揉燃,去河邊找鬼。 笑死筋栋,一個胖子當(dāng)著我的面吹牛炊汤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼婿崭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肴颊?” 一聲冷哼從身側(cè)響起氓栈,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎婿着,沒想到半個月后授瘦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡竟宋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年提完,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丘侠。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡徒欣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜗字,到底是詐尸還是另有隱情打肝,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布挪捕,位于F島的核電站粗梭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏级零。R本人自食惡果不足惜断医,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奏纪。 院中可真熱鬧鉴嗤,春花似錦、人聲如沸序调。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炕置。三九已至荣挨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朴摊,已是汗流浹背默垄。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留甚纲,地道東北人口锭。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹃操。 傳聞我的和親對象是個殘疾皇子韭寸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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

  • 那是開學(xué)之初,夏日的太陽顯得不是太熱烈荆隘,在一群穿著校服的大二學(xué)長學(xué)姐們中間恩伺,她一眼就看到了那個異常好看的男孩子,有...
    你家有個小金毛閱讀 313評論 0 1
  • 如果老實說的話椰拒,是四位晶渠,可惜的是那兩位,一位怕是永遠(yuǎn)都見不到的那種燃观,還有一位褒脯,是你所忌諱的。我所能真正表達(dá)的...
    Ianvono閱讀 227評論 0 0
  • 中國本來是地大物博缆毁,人才擠擠番川,現(xiàn)在還行,只不過有些國家還是虎視眈眈脊框,想把中國的土地給自己爽彤,回想過去,在元明清時缚陷,地...
    王玉笙閱讀 127評論 0 0
  • 要錢适篙,就要努力干活,要美美的箫爷,就要努力保養(yǎng)嚷节,要成為聰明的人,就要努力讀書虎锚,要有很多朋友硫痰,就要慷慨而熱情。 ...
    樑生閱讀 234評論 0 0
  • 2018-8-7 指間的溫度_55e7 2018-8-708:53 · 字?jǐn)?shù) 175 · 閱讀 9 · 日記本 2...
    指間的溫度_55e7閱讀 126評論 0 0