精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試必問:hashmap為什么會出現死循環?

新聞
jdk1.7 hashmap的循環依賴問題是面試經常被問到的問題,如何回答不好,可能會被扣分。今天我就帶大家一下梳理一下,這個問題是如何產生的,以及如何解決這個問題。

jdk1.7 hashmap的循環依賴問題是面試經常被問到的問題,如何回答不好,可能會被扣分。今天我就帶大家一下梳理一下,這個問題是如何產生的,以及如何解決這個問題。

一、hashmap的數據結構

先一起看看jdk1.7 hashmap的數據結構

數組 + 鏈表

hashmap會給每個元素的key生成一個hash值,然后根據這個hash值計算一個在數組中的位置i。i不同的元素放在數組的不同位置,i相同的元素放在鏈表上,最新的數據放在鏈表的頭部。

往hashmap中保存元素會調用put方法,獲取元素會調用get方法。接下來,我們重點看看put方法。

二、put方法

重點看看put方法

  1. public V put(K key, V value) { 
  2.     if (table == EMPTY_TABLE) { 
  3.         inflateTable(threshold);    }    if (key == null
  4.         return putForNullKey(value); 
  5.     //根據key獲取hash      
  6.     int hash = hash(key);    //計算在數組中的下表 
  7.     int i = indexFor(hash, table.length);    //變量集合查詢相同key的數據,如果已經存在則更新數據 
  8.     for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
  9.         Object k;        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
  10.             V oldValue = e.value;            e.value = value;            e.recordAccess(this);            //返回已有數據 
  11.             return oldValue; 
  12.         }    }    modCount++;    //如果不存在相同key的元素,則添加新元素 
  13.     addEntry(hash, key, value, i);    return null

再看看addEntry方法

  1. void addEntry(int hash, K key, V value, int bucketIndex) { 
  2.       // 當數組的size >= 擴容閾值,觸發擴容,size大小會在createEnty和removeEntry的時候改變      if ((size >= threshold) && (null != table[bucketIndex])) { 
  3.           // 擴容到2倍大小,后邊會跟進這個方法          resize(2 * table.length);          // 擴容后重新計算hash和index 
  4.           hash = (null != key) ? hash(key) : 0; 
  5.           bucketIndex = indexFor(hash, table.length); 
  6.       }      // 創建一個新的鏈表節點,點進去可以了解到是將新節點添加到了鏈表的頭部      createEntry(hash, key, value, bucketIndex); 
  7.   } 

看看resize是如何擴容的

  1. void resize(int newCapacity) { 
  2.         Entry[] oldTable = table;        int oldCapacity = oldTable.length; 
  3.         if (oldCapacity == MAXIMUM_CAPACITY) { 
  4.             threshold = Integer.MAX_VALUE;            return
  5.         }        // 創建2倍大小的新數組 
  6.         Entry[] newTable = new Entry[newCapacity]; 
  7.         // 將舊數組的鏈表轉移到新數組,就是這個方法導致的hashMap不安全,等下我們進去看一眼 
  8.         transfer(newTable, initHashSeedAsNeeded(newCapacity)); 
  9.         table = newTable; 
  10.         // 重新計算擴容閾值(容量*加載因子) 
  11.         threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); 

出問題的就是這個transfer方法

  1. void transfer(Entry[] newTable, boolean rehash) { 
  2.     int newCapacity = newTable.length;    // 遍歷舊數組 
  3.     for (Entry<K,V> e : table) { 
  4.         // 遍歷鏈表 
  5.         while(null != e) { 
  6.              //獲取下一個元素,記錄到一個臨時變量,以便后面使用 
  7.             Entry<K,V> next = e.next
  8.             if (rehash) { 
  9.                 e.hash = null == e.key ? 0 : hash(e.key); 
  10.             }            // 計算節點在新數組中的下標 
  11.             int i = indexFor(e.hash, newCapacity); 
  12.             // 將舊節點插入到新節點的頭部 
  13.             e.next = newTable[i]; 
  14.             //這行才是真正把數據插入新數組中,前面那行代碼只是設置當前節點的next 
  15.             //這兩行代碼決定了倒序插入 
  16.             //比如:以前同一個位置上是:3,7,后面可能變成了:7、3 
  17.             newTable[i] = e; 
  18.             //將下一個元素賦值給當前元素,以便遍歷下一個元素 
  19.             e = next
  20.         } 
  21.     } 

我來給大家分析一下,為什么這幾個代碼是頭插法,網上很多技術文章都沒有說清楚。

三、頭插法

我們把目光聚焦到這幾行代碼:

  1. //獲取下一個元素,記錄到一個臨時變量,以便后面使用 
  2.   Entry<K,V> next = e.next
  3.   // 計算節點在新數組中的下標  int i = indexFor(e.hash, newCapacity);  // 將舊節點插入到新節點的頭部  e.next = newTable[i]; 
  4.   //這行才是真正把數據插入新數組中,前面那行代碼只是設置當前節點的next 
  5.   newTable[i] = e;  //將下一個元素賦值給當前元素,以便遍歷下一個元素  e = next

假設剛開始hashMap有這些數據

調用put方法需要進行一次擴容,剛開始會創建一個空的數組,大小是以前的2倍,如圖所示:

開始第一輪循環:

  1. //next= 7   e = 3  e.next = 7 
  2. Entry<K,V> next = e.next
  3. // i=3 
  4. int i = indexFor(e.hash, newCapacity);//e.next = null ,剛初始化時新數組的元素為null 
  5. e.next = newTable[i]; 
  6. //給新數組i位置 賦值 3 
  7. newTable[i] = e;// e = 7 
  8. e = next

執行完之后,第一輪循環之后數據變成這樣的

再接著開始第二輪循環:

  1. //next= 5   e = 7  e.next = 5 
  2. Entry<K,V> next = e.next
  3. // i=3 
  4. int i = indexFor(e.hash, newCapacity);//e.next = 3 ,此時相同位置上已經有key=3的值了,將該值賦值給當前元素的next 
  5. e.next = newTable[i]; 
  6. //給新數組i位置 賦值 7 
  7. newTable[i] = e;// e = 5 
  8. e = next

上面會構成一個新鏈表,連接的順序正好反過來了。

由于第二次循環時,節點key=7的元素插到相同位置上已有元素key=3的前面,所以說是采用的頭插法。

四、死循環的產生

接下來重點看看死循環是如何產生的?

假設數據跟元素數據一致,有兩個線程:線程1 和 線程2,同時執行put方法,最后同時調用transfer方法。

線程1 先執行,到 Entry next = e.next; 這一行,被掛起了。

  1. //next= 7   e = 3  e.next = 7 
  2. Entry<K,V> next = e.next
  3. int i = indexFor(e.hash, newCapacity);e.next = newTable[i]; 
  4. newTable[i] = e;e = next

此時線程1 創建的數組會創建一個空數組

接下來,線程2開始執行,由于線程2運氣比較好,沒有被中斷過,執行完畢了。

過一會兒,線程1被恢復了,重新執行代碼。

  1. //next= 7   e = 3  e.next = 7 
  2. Entry<K,V> next = e.next
  3. // i = 3 
  4. int i = indexFor(e.hash, newCapacity);// e.next = null,剛初始化時新數組的元素為null 
  5. e.next = newTable[i]; 
  6. // 給新數組i位置 賦值 3 
  7. newTable[i] = e;// e = 7 
  8. e = next

這時候線程1的數組會變成這樣的

再執行第二輪循環,此時的e=7

  1. //next= 3   e = 7  e.next = 3 
  2. Entry<K,V> next = e.next
  3. // i = 3 
  4. int i = indexFor(e.hash, newCapacity);// e.next = 3,此時相同位置上已經有key=3的值了,將該值賦值給當前元素的next 
  5. e.next = newTable[i]; 
  6. // 給新數組i位置 賦值 7 
  7. newTable[i] = e;// e = 3 
  8. e = next

這里特別要說明的是 此時e=7,而e.next為什么是3呢?

因為hashMap的數據是公共的,還記得線程2中的生成的數據嗎?

此時e=7,那么e.next肯定是3。

經過上面第二輪循環之后,線程1得到的數據如下:

此時由于循環判斷還沒有退出,判斷條件是: while(null != e),所以要開始第三輪循環:

  1. //nextnull   e = 3  e.next = null 
  2. Entry<K,V> next = e.next
  3. // i = 3 
  4. int i = indexFor(e.hash, newCapacity);// e.next = 7,關鍵的一步,由于第二次循環是 key:7 .next = key:3,現在key:3.next = key:7 
  5. e.next = newTable[i]; 
  6. // 給新數組i位置 賦值 3 
  7. newTable[i] = e;// e = nulle = next

由于e=null,此時會退出循環,最終線程1的數據會是這種結構:

key:3 和 key:7又恢復了剛開始的順序,但是他們的next會相互引用,構成環形引用。

注意,此時調用hashmap的get方法獲取數據時,如果只是獲取循環鏈上key:3 和 key:7的數據,是不會有問題的,因為可以找到。就怕獲取循環鏈上沒有的數據,比如:key:11,key:15等,會進入無限循環中導致CPU使用率飆升。

五、如何避免死循環

為了解決這個問題,jdk1.8把擴容是復制元素到新數組由 頭插法 改成了 尾插法 。此外,引入了紅黑樹,提升遍歷節點的效率。在這里我就不過多介紹了,如果有興趣的朋友,可以關注我的公眾號,后面會給大家詳細分析jdk1.8的實現,以及 jdk1.7、jdk1.8 hashmap的區別。

此外,HashMap是非線程安全的,要避免在多線程的環境中使用HashMap,而應該改成使用ConcurrentHashMap。

所以總結一下要避免發生死循環的問題的方法:

  • 改成ConcurrentHashMap

PS. 即使JDK升級到1.8任然有死循環的問題。

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2022-01-18 06:59:50

HashMap循環底層

2022-01-20 08:44:25

HashMap死循環開放性

2013-06-06 13:34:56

HashMap線程不安全

2023-02-03 07:24:49

雙親委派模型

2011-05-17 08:58:29

軟件項目經理

2020-12-17 07:39:30

HashMap死循環數據

2025-01-21 00:00:00

HashMap死循環數據損壞

2023-02-01 07:15:16

2023-02-17 08:02:45

@Autowired@Resource

2021-12-09 12:22:28

MyBatis流程面試

2023-06-07 08:08:43

JVM內存模型

2020-07-28 08:59:22

JavahreadLocal面試

2023-05-15 08:34:36

css浮動

2023-02-15 07:03:41

跨域問題面試安全

2022-06-18 23:10:56

前端模塊循環依賴

2020-03-27 10:08:10

JS異步 I

2021-12-06 11:03:57

JVM性能調優

2021-12-27 08:22:18

Kafka消費模型

2020-10-12 18:00:39

JavaAQS代碼

2020-05-27 12:45:52

HashMapJava加載因子
點贊
收藏

51CTO技術棧公眾號

久久久青草婷婷精品综合日韩| 欧美人妖视频| 亚洲线精品一区二区三区| 国产精品我不卡| 青娱乐在线免费视频| 婷婷亚洲图片| 日韩高清有码在线| 久久婷婷综合色| 国产天堂在线播放视频| 2014亚洲片线观看视频免费| 成人妇女免费播放久久久| 久久久久久欧美精品se一二三四| 丝袜连裤袜欧美激情日韩| 欧美日韩精品一区二区天天拍小说 | 尤物视频免费观看| 中文字幕人成人乱码| 精品性高朝久久久久久久| 成人亚洲免费视频| 亚洲美女尤物影院| 亚洲精品videosex极品| 日本黄网免费一区二区精品| 丁香六月色婷婷| 美女视频一区在线观看| 欧美一级大片在线观看| 午夜少妇久久久久久久久| 国产精品欧美日韩一区| 精品国产1区2区3区| 色播五月综合网| 性国裸体高清亚洲| 一区二区视频在线| 亚洲综合av一区| 青春草在线观看| 成人av免费在线播放| 91在线视频免费| 日韩一级片中文字幕| 在线欧美视频| 欧美俄罗斯性视频| 欧美丰满熟妇bbbbbb| 精品99在线| 亚洲男人的天堂网站| 国产女人18毛片水真多18| 狂野欧美xxxx韩国少妇| 欧美精品xxxxbbbb| 欧美精品性生活| 欧美亚洲韩国| 一本久久精品一区二区| 免费黄色福利视频| 97成人资源| 欧美视频在线免费| 国模吧无码一区二区三区| av资源在线播放| 亚洲成av人片| 欧美黑人经典片免费观看| av福利在线导航| 亚洲国产wwwccc36天堂| www.国产在线视频| 国产区美女在线| 亚洲第一福利视频在线| 国产乱子伦精品无码专区| a毛片在线看免费观看| 亚洲日本韩国一区| 丰满人妻一区二区三区53号| 色屁屁www国产馆在线观看| 亚洲自拍偷拍网站| 男女激情免费视频| 特黄毛片在线观看| 在线一区二区三区| 鲁一鲁一鲁一鲁一av| 涩涩涩久久久成人精品| 欧美精品一级二级| 国产高潮失禁喷水爽到抽搐 | 91精品国产91久久久久久最新毛片 | 开心色怡人综合网站| 日本毛片在线观看| 2023国产精品自拍| 一本色道久久99精品综合| 欧美精品日韩少妇| 一区二区免费视频| 91视频最新入口| 全球中文成人在线| 欧美变态口味重另类| 亚洲av成人片色在线观看高潮| 色天下一区二区三区| 亚洲视频第一页| 99久久久免费精品| 亚洲三级视频| 国产精品视频久久| 高清一区二区三区四区| 91在线免费播放| 亚洲精品不卡| 懂色av一区| 91久久精品日日躁夜夜躁欧美| 亚洲精品国产久| 丝袜美腿综合| 久久国产加勒比精品无码| 日韩欧美一区二区一幕| 老司机免费视频久久| 成人性生交大片免费看视频直播 | 久久色.com| 国产又大又长又粗又黄| 男女羞羞在线观看| 4hu四虎永久在线影院成人| www.男人天堂| 日韩理论在线| 2019亚洲男人天堂| 国产情侣av在线| 久久亚洲免费视频| av中文字幕av| 69堂精品视频在线播放| 日韩你懂的在线播放| 成人无码av片在线观看| 在线 亚洲欧美在线综合一区| 国产精品久久久久久久久久久久久久 | 一区二区欧美亚洲| 久久久久久久久久久网 | 婷婷成人激情| 欧美日韩亚洲视频一区| 爱情岛论坛亚洲自拍| 国产欧美日韩在线一区二区| 久久久久国产一区二区三区| 亚洲一区二区色| 久久精品亚洲麻豆av一区二区| www插插插无码免费视频网站| 91精品韩国| 亚洲经典中文字幕| 欧美色图亚洲天堂| 美女看a上一区| 日本不卡久久| 亚洲最新无码中文字幕久久| 亚洲电影免费观看高清完整版在线观看 | 免费污网站在线观看| 亚洲乱亚洲高清| 97人人模人人爽人人少妇| 亚洲乱亚洲乱妇| 在线观看亚洲精品视频| 欧美大片免费播放器| 亚洲二区视频| 成人蜜桃视频| 丝袜中文在线| 91精品福利在线一区二区三区| 天堂av网手机版| 天堂一区二区在线| 欧美日韩在线观看一区| 九色porny自拍视频在线播放| 欧美成人r级一区二区三区| 日韩欧美中文字幕视频| 狠狠网亚洲精品| 在线观看一区二区三区三州| 精品久久99| 日韩视频在线一区| 这里只有精品6| 亚洲国产激情av| 在线黄色免费观看| 91日韩欧美| 91在线视频九色| 亚洲精品一线| 精品国产一区二区精华| 久草视频精品在线| 91影院在线免费观看| 青青青在线播放| 清纯唯美日韩| 91精品视频在线看| 色老头在线观看| 精品国产91洋老外米糕| 日韩欧美性视频| 久久久精品影视| 欧美三级午夜理伦三级富婆| 香港欧美日韩三级黄色一级电影网站| 成人国产精品色哟哟| 手机在线免费观看av| 精品国产凹凸成av人网站| 日本韩国欧美中文字幕| 中文久久乱码一区二区| aaaaaaaa毛片| 国产美女一区| 亚洲精品一区二区三区四区五区 | 国产精品制服诱惑| 黄色在线观看www| 亚洲深夜福利视频| 国产视频第二页| 午夜av区久久| 欧美黄色一级生活片| 精品一区二区三区免费毛片爱| 好色先生视频污| 日韩成人午夜| 成人性生交大片免费观看嘿嘿视频| 日本大胆在线观看| 亚洲性线免费观看视频成熟| 国产乱色精品成人免费视频| 亚洲成人综合视频| 免费在线观看a视频| 国内不卡的二区三区中文字幕 | 成人欧美magnet| 日韩亚洲精品视频| 黑人操亚洲女人| 欧美网站大全在线观看| 免费看一级一片| 亚洲国产高清不卡| 亚洲精品乱码久久| 狠狠色丁香婷综合久久| 丰满少妇被猛烈进入高清播放| 欧美国产一区二区三区激情无套| 国产成人精品日本亚洲11| 日韩中文在线播放| 国内精品久久久久久影视8| 懂色av中文在线| 日韩av在线网| 国产按摩一区二区三区| 欧美专区亚洲专区| 日韩精品久久久久久久| 国产精品福利一区| 国产一二三四五区| 成人丝袜高跟foot| 午夜精品免费看| 丝袜美腿一区二区三区| 无码 制服 丝袜 国产 另类| 欧美国产一级| 日韩视频精品| 精品一区三区| 精选一区二区三区四区五区| 欧美欧美在线| 国产欧美一区二区三区久久人妖 | 欧美疯狂性受xxxxx喷水图片| 国产成人精品网| 亚洲国产精品嫩草影院| 国产老头老太做爰视频| 国产女主播在线一区二区| 亚洲中文字幕一区| 国产91精品一区二区麻豆亚洲| jizz18女人| 奇米影视一区二区三区| 免费日韩中文字幕| 亚洲激情视频| 日韩av新片网| 激情成人综合| www.日本少妇| 狠狠噜噜久久| 日韩国产成人无码av毛片| 日本a口亚洲| 亚洲人成网站在线播放2019| 国产精品一区二区av交换| 精品久久sese| 小嫩嫩12欧美| 欧美日韩国产免费一区二区三区 | 免费污视频在线一区| 国产99视频精品免视看7| 性爽视频在线| 日本在线观看天堂男亚洲 | 免费看污黄网站在线观看| 99久久精品免费精品国产| 久久久久久婷婷| 91在线免费视频观看| 波多野结衣av在线免费观看| 91免费视频网| 先锋影音av在线| 亚洲国产精品精华液ab| 永久免费未视频| 亚洲三级小视频| 美女毛片在线观看| 亚洲成av人影院在线观看网| www.av视频在线观看| 精品高清一区二区三区| 国产suv精品一区二区33| 欧美视频中文字幕| a级片在线视频| 精品欧美一区二区在线观看| 特黄aaaaaaaaa真人毛片| 日韩精品久久久久久久玫瑰园| 色窝窝无码一区二区三区| 日韩电影中文字幕一区| www在线免费观看| 免费91麻豆精品国产自产在线观看| 国产在线拍揄自揄拍视频| 欧美孕妇性xx| 亚洲成人高清| 国产免费高清一区| 免费久久久久久久久| 亚洲国产欧美不卡在线观看| 午夜国产精品视频| 国产特级淫片高清视频| 日本欧美韩国一区三区| 男插女视频网站| 91蝌蚪国产九色| 精品女人久久久| 午夜电影一区二区| 中文字幕一二三四| 精品国产精品网麻豆系列| 国产在线一二| 欧美高清在线观看| 色综合一本到久久亚洲91| 99久热re在线精品996热视频| 亚洲盗摄视频| 看一级黄色录像| 久久aⅴ国产紧身牛仔裤| 中文字幕永久有效| 99视频在线精品| 在线看的片片片免费| 色综合久久久久综合99| 99热这里只有精| 亚洲日本aⅴ片在线观看香蕉| dj大片免费在线观看| 国产成人综合av| 好吊妞视频这里有精品| 一区二区三区精品国产| 亚洲欧美清纯在线制服| 成人三级做爰av| 国产欧美日韩久久| 日韩av男人天堂| 欧美一二三区在线观看| 成人av一区| 欧美怡红院视频一区二区三区| 国产高清亚洲| 色涩成人影视在线播放| 亚洲国产电影| 久久无码专区国产精品s| 国产精品免费网站在线观看| 日韩欧美一区二区一幕| 日韩久久精品一区| 69视频在线| 国产v综合ⅴ日韩v欧美大片| 国产调教精品| 久久福利一区二区| 精品一区二区三区蜜桃| 欧美丰满老妇熟乱xxxxyyy| 色综合久久66| 日韩二区三区| 欧美亚洲国产日韩2020| 国产福利资源一区| 久草视频国产在线| 国产精品白丝jk黑袜喷水| 黄色录像一级片| 欧美日韩成人综合| sese一区| 国产日韩欧美中文| 大色综合视频网站在线播放| 国产偷人视频免费| 久久夜色精品一区| 日日噜噜噜噜人人爽亚洲精品| 亚洲国产精品热久久| 97人澡人人添人人爽欧美| 国产伦精品一区二区三区视频免费 | 久久精品视频2| 亚洲另类图片色| 97成人资源| 视频一区国产精品| 日韩国产高清在线| 波多野结衣一二三四区| 欧美色区777第一页| 日本在线观看| 成人欧美一区二区三区在线湿哒哒 | 国产情侣自拍av| 日韩精品视频免费在线观看| 成人爽a毛片免费啪啪| 欧美一区二区三区成人久久片| 久久精品官网| 国产极品视频在线观看| 欧美日韩精品一区二区| 免费在线观看av| 亚洲曰本av电影| 亚洲国产精品一区| 国产精品无码一区二区三区免费 | 国产精品午夜福利| 欧美精品在线播放| 国产成人高清精品免费5388| 免费 成 人 黄 色| 欧美激情一区二区三区蜜桃视频| 中文字幕乱伦视频| 久久在精品线影院精品国产| 日本成人精品| 欧美日韩成人免费视频| 久久久国产精华| 国产精品污视频| 国内精品久久久久久久久| 久久不见久久见国语| 国产福利在线免费| 亚洲小说欧美激情另类| 日本福利在线观看| 国产精品偷伦免费视频观看的| 一区二区三区四区电影| 一区二区免费在线观看视频| 在线精品亚洲一区二区不卡| 国产欧美久久久久久久久| 好吊色欧美一区二区三区| 青椒成人免费视频| 天天干中文字幕| 国产视频精品免费播放| 亚洲91在线| 日韩在线综合网| 亚洲欧洲色图综合| 天天干,天天操,天天射| 国产女精品视频网站免费| 欧美特黄a级高清免费大片a级| 免费黄色在线视频| 日韩女优av电影| 成人免费一区| 热99这里只有精品| 日韩理论片在线| 欧美孕妇孕交xxⅹ孕妇交| 91亚洲国产成人精品性色| 免费视频久久|