日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并发的HashMap为什么会引起死循环?(转)

發(fā)布時間:2025/7/25 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发的HashMap为什么会引起死循环?(转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文轉(zhuǎn)自http://blog.csdn.net/zhuqiuhui/article/details/51849692

今天研讀Java并發(fā)容器和框架時,看到為什么要使用ConcurrentHashMap時,其中有一個原因是:線程不安全的HashMap, HashMap在并發(fā)執(zhí)行put操作時會引起死循環(huán),是因為多線程會導致HashMap的Entry鏈表形成環(huán)形數(shù)據(jù)結構,查找時會陷入死循環(huán)。糾起原因看了其他的博客,都比較抽象,所以這里以圖形的方式展示一下,希望支持!

?

(1)當往HashMap中添加元素時,會引起HashMap容器的擴容,原理不再解釋,直接附源代碼,如下:

[java]?view plaincopy
  • /**??
  • ????*??
  • ????*?往表中添加元素,如果插入元素之后,表長度不夠,便會調(diào)用resize方法擴容??
  • ????*/????
  • ???void?addEntry(int?hash,?K?key,?V?value,?int?bucketIndex)?{????
  • Entry<K,V>?e?=?table[bucketIndex];????
  • ???????table[bucketIndex]?=?new?Entry<K,V>(hash,?key,?value,?e);????
  • ???????if?(size++?>=?threshold)????
  • ???????????resize(2?*?table.length);????
  • ???}????
  • ????
  • ???/**??
  • ????*?resize()方法如下,重要的是transfer方法,把舊表中的元素添加到新表中?
  • ????*/????
  • ???void?resize(int?newCapacity)?{????
  • ???????Entry[]?oldTable?=?table;????
  • ???????int?oldCapacity?=?oldTable.length;????
  • ???????if?(oldCapacity?==?MAXIMUM_CAPACITY)?{????
  • ???????????threshold?=?Integer.MAX_VALUE;????
  • ???????????return;????
  • ???????}????
  • ????
  • ???????Entry[]?newTable?=?new?Entry[newCapacity];????
  • ???????transfer(newTable);????
  • ???????table?=?newTable;????
  • ???????threshold?=?(int)(newCapacity?*?loadFactor);????
  • ???}????
  • (2)參考上面的代碼,便引入到了transfer方法,(引入重點)這就是HashMap并發(fā)時,會引起死循環(huán)的根本原因所在,下面結合transfer的源代碼,說明一下產(chǎn)生死循環(huán)的原理,先列transfer代碼(這是里JDK7的源偌),如下:

    [java]?view plaincopy
  • /**?
  • ?????*?Transfers?all?entries?from?current?table?to?newTable.?
  • ?????*/??
  • ????void?transfer(Entry[]?newTable,?boolean?rehash)?{??
  • ????????int?newCapacity?=?newTable.length;??
  • ????????for?(Entry<K,V>?e?:?table)?{??
  • ??
  • ????????????while(null?!=?e)?{??
  • ????????????????Entry<K,V>?next?=?e.next;????????????---------------------(1)??
  • ????????????????if?(rehash)?{??
  • ????????????????????e.hash?=?null?==?e.key???0?:?hash(e.key);??
  • ????????????????}??
  • ????????????????int?i?=?indexFor(e.hash,?newCapacity);???
  • ????????????????e.next?=?newTable[i];??
  • ????????????????newTable[i]?=?e;??
  • ????????????????e?=?next;??
  • ????????????}?//?while??
  • ??
  • ????????}??
  • ????}??
  • ?

    ?

    (3)假設:

    [java]?view plaincopy
  • Map<Integer>?map?=?new?HashMap<Integer>(2);??//?只能放置兩個元素,其中的threshold為1(表中只填充一個元素時),即插入元素為1時就擴容(由addEntry方法中得知)??
  • //放置2個元素?3?和?7,若要再放置元素8(經(jīng)hash映射后不等于1)時,會引起擴容??
  • 假設放置結果圖如下:

    ? ? ?

    ?現(xiàn)在有兩個線程A和B,都要執(zhí)行put操作,即向表中添加元素,即線程A和線程B都會看到上面圖的狀態(tài)快照

    執(zhí)行順序如下:

    ? ? ? ? ? ? ? ?執(zhí)行一: ?線程A執(zhí)行到transfer函數(shù)中(1)處掛起(transfer函數(shù)代碼中有標注)。此時在線程A的棧中

    ?

    [java]?view plaincopy
  • e?=?3??
  • next?=?7??
  • ?

    ?

    ? ? ? ? ? ? ? 執(zhí)行二:線程B執(zhí)行 transfer函數(shù)中的while循環(huán),即會把原來的table變成新一table(線程B自己的棧中),再寫入到內(nèi)存中。如下圖(假設兩個元素在新的hash函數(shù)下也會映射到同一個位置)

    ? ? ? ? ? ? ?執(zhí)行三: 線程A解掛,接著執(zhí)行(看到的仍是舊表),即從transfer代碼(1)處接著執(zhí)行,當前的 e = 3, next = 7, 上面已經(jīng)描述。

    ? ? ? ? ? ? ? ? ? ? ? ? ??

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1. 處理元素 3 , 將 3 放入 線程A自己棧的新table中(新table是處于線程A自己棧中,是線程私有的,不肥線程2的影響),處理3后的圖如下:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2. ?線程A再復制元素 7 ,當前 e = 7 ,而next值由于線程 B 修改了它的引用,所以next 為 3 ,處理后的新表如下圖

    ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ?3. 由于上面取到的next = 3, 接著while循環(huán),即當前處理的結點為3, next就為null ,退出while循環(huán),執(zhí)行完while循環(huán)后,新表中的內(nèi)容如下圖:

    ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4. 當操作完成,執(zhí)行查找時,會陷入死循環(huán)!

    ?

    ?

    下文轉(zhuǎn)自https://www.cnblogs.com/yjbjingcha/p/6957909.html

    HashMap在高并發(fā)下引起的死循環(huán)

    HashMap事實上并非線程安全的,在高并發(fā)的情況下,是非常可能發(fā)生死循環(huán)的,由此造成CPU 100%,這是非常可怕的。所以在多線程的情況下,用HashMap是非常不妥當?shù)男袨?#xff0c;應採用線程安全類ConcurrentHashMap進行取代。

    ?

    ?

    HashMap死循環(huán)原因

    ?

    HashMap進行存儲時,假設size超過當前最大容量*負載因子時候會發(fā)生resize。首先看一下resize原代碼

    ?

    ?

    void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];transfer(newTable);table = newTable;threshold = (int)(newCapacity * loadFactor);}
    而這段代碼中又調(diào)用了transfer()方法,而這種方法實現(xiàn)的機制就是將每一個鏈表轉(zhuǎn)化到新鏈表,而且鏈表中的位置發(fā)生反轉(zhuǎn),而這在多線程情況下是非常easy造成鏈表回路。從而發(fā)生get()死循環(huán)。我們看一下他的源碼

    ?

    ?

    void transfer(Entry[] newTable) {Entry[] src = table;int newCapacity = newTable.length;for (int j = 0; j < src.length; j++) {Entry<K,V> e = src[j];if (e != null) {src[j] = null;do {Entry<K,V> next = e.next;int i = indexFor(e.hash, newCapacity);e.next = newTable[i];newTable[i] = e;e = next;} while (e != null);}}}

    ?

    ?

    HashMap死循環(huán)演示

    假如有兩個線程P1、P2,以及鏈表 a=》b=》null

    ?

    1、P1先運行,運行完"Entry<K,V> next = e.next;"代碼后發(fā)生堵塞,或者其它情況不再運行下去,此時e=a。next=b

    2、而P2已經(jīng)運行完整段代碼,于是當前的新鏈表newTable[i]為b=》a=》null

    3、P1又繼續(xù)運行"Entry<K,V> next = e.next;"之后的代碼,則運行完"e=next;"后,newTable[i]為a《=》b。則造成回路,while(e!=null)一直死循環(huán)

    ?

    ?

    總結

    HashMap并不是線程安全,所以在多線程情況下,應該首先考慮用ConcurrentHashMap。避免悲劇的發(fā)生

    ?

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/panxuejun/p/8577410.html

    總結

    以上是生活随笔為你收集整理的并发的HashMap为什么会引起死循环?(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久这里都是精品 | 欧美一级特黄aaaaaa大片在线观看 | 深夜免费福利视频 | 久久成人人人人精品欧 | 国产乱叫456在线 | 国产剧情一区二区 | 蜜臀久久99精品久久久无需会员 | www.黄色大片 | 二级黄色片 | 六月婷婷七月丁香 | 免费一级淫片 | 免费操片| 麻豆chinese新婚xxx| 免费三级网 | 免费裸体美女网站 | 天天看天天干 | 天堂在线免费观看 | 久久黄色网 | sm调教羞耻姿势图片 | 成人必看www.| 巨茎大战刘亦菲 | 波多野结衣1区2区3区 | 国产精品羞羞答答在线 | 熟妇人妻av无码一区二区三区 | 麻豆传媒在线观看视频 | 日韩女同互慰一区二区 | 国产又猛又黄又爽 | 99久久婷婷国产综合精品青牛牛 | 日韩成人自拍 | gv天堂gv无码男同在线观看 | 狠狠干伊人 | 日本老妇性生活 | 高贵麻麻被调教成玩物 | 粉嫩av在线 | 日韩电影二区 | 伊人久久综合视频 | 黄视频网站免费看 | 国产成人精品在线 | 日韩在线1| 国产妇女乱一性一交 | 91色精品 | 狠狠干干干 | 久久久精品久久久久 | 一区二区三区黄色片 | 国产熟女一区二区三区五月婷 | 三年中文在线观看中文版 | 精品综合久久久 | 日韩一区二区视频 | 91中文字幕| 另类在线视频 | 最好看的2019中文大全在线观看 | 久久艳片www.17c.com | 欧美怡红院视频一区二区三区 | 做暧暧视频在线观看 | 亚洲黄色成人 | 日日摸日日干 | 毛片视频免费 | 久久国产精品精品国产色婷婷 | 丁香激情网 | 天天夜夜啦啦啦 | 国产福利一区在线观看 | a级片视频网站 | 蜜臀少妇久久久久久久高潮 | 97视频资源| 成人免费精品 | 特黄特色大片免费播放器使用方法 | 综合网在线观看 | 美女一级黄色片 | 轻点好疼好大好爽视频 | 香蕉久久国产 | 亚洲一区二区三区四区五区xx | 天天撸天天操 | 黄黄视频在线观看 | av在线免费不卡 | 自拍偷拍999 | 人人九九 | 国产福利在线导航 | 久久看片 | 国产欧美日韩综合精品一区 | 巨乳美女被爆操 | 少妇 av | 欧美一二三视频 | 久久亚洲综合色图 | 无码av免费毛片一区二区 | 欧美高清视频一区二区 | 激情综合视频 | 久久性生活视频 | 99国产精品久久久久99打野战 | 97天天干 | 日日噜噜噜 | 中国少妇无码专区 | 午夜激情网址 | 护士的小嫩嫩好紧好爽 | 日韩五十路 | 亚洲AV永久无码国产精品国产 | 成人网站免费观看 | 日韩视频在线免费观看 | 欧美日韩在线视频一区二区三区 | 日韩欧美视频二区 |