欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關于HashMap 并發(fā)時會引起死循環(huán)的問題解析

 更新時間:2021年05月26日 09:58:43   作者:bboyzqh  
JDK1.8之前采用頭插,即在鏈表結構上每次都把數據放在鏈表頭部。JDK1.8采用尾插方法,很多朋友在學習Java并發(fā)容器和框架時,看到為什么要使用ConcurrentHashMap時不知道究其原因,今天小編通過本文給大家介紹下HashMap 并發(fā)死循環(huán)問題,一起看看吧

今天研讀Java并發(fā)容器和框架時,看到為什么要使用ConcurrentHashMap時,其中有一個原因是:線程不安全的HashMap, HashMap在并發(fā)執(zhí)行put操作時會引起死循環(huán),是因為多線程會導致HashMap的Entry鏈表形成環(huán)形數據結構,查找時會陷入死循環(huán)。

糾起原因看了其他的博客,都比較抽象,所以這里以圖形的方式展示一下,希望支持!

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

/** 
* 
* 往表中添加元素,如果插入元素之后,表長度不夠,便會調用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的源代碼,說明一下產生死循環(huán)的原理,先列transfer代碼(這是里JDK7的源偌),如下:

/**
 * 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)假設:

Map<Integer> map = new HashMap<Integer>(2);  // 只能放置兩個元素,其中的threshold為1(表中只填充一個元素時),即插入元素為1時就擴容(由addEntry方法中得知)
//放置2個元素 3 和 7,若要再放置元素8(經hash映射后不等于1)時,會引起擴容

假設放置結果圖如下:

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

執(zhí)行順序如下:

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

e = 3
next = 7

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

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

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)后,新表中的內容如下圖:

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

原文鏈接:https://blog.csdn.net/zhuqiuhui/article/details/51849692

版權聲明:本文為CSDN博主「bboyzqh」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。

以上就是關于HashMap 并發(fā)時會引起死循環(huán)的問題解析的詳細內容,更多關于HashMap 并發(fā)死循環(huán)的資料請關注腳本之家其它相關文章!

相關文章

  • java實現(xiàn)簡單租車系統(tǒng)

    java實現(xiàn)簡單租車系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)簡單租車系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 詳解Java中“==”與equals()的區(qū)別

    詳解Java中“==”與equals()的區(qū)別

    這篇文章主要介紹了詳解Java中“==”與equals()的區(qū)別的相關資料,需要的朋友可以參考下
    2017-02-02
  • 使用SpringJPA?直接實現(xiàn)count(*)

    使用SpringJPA?直接實現(xiàn)count(*)

    這篇文章主要介紹了SpringJPA?直接實現(xiàn)count(*),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java中Stream?Filter多條件篩選過濾代碼舉例

    Java中Stream?Filter多條件篩選過濾代碼舉例

    這篇文章主要給大家介紹了關于Java中Stream?Filter多條件篩選過濾的相關資料,Java Stream中的filter方法可以使用多個條件來過濾數據,文中給出了詳細的代碼示例,需要的朋友可以參考下
    2023-12-12
  • java異常處理執(zhí)行順序詳解try catch finally

    java異常處理執(zhí)行順序詳解try catch finally

    try catch語句是java語言用于捕獲異常并進行處理的標準方式,對于try catch及try catch finally執(zhí)行順序必須有深入的了解
    2021-10-10
  • Spring條件注解沒生效該如何解決

    Spring條件注解沒生效該如何解決

    條件注解相信各位小伙伴都用過,Spring?中的多環(huán)境配置?profile?底層就是通過條件注解來實現(xiàn)的,下面小編就來為大家介紹一下當Spring條件注解沒生效時該如何解決,感興趣的可以了解下
    2023-09-09
  • 利用IDEA工具修改Maven多模塊項目標識包名全過程記錄

    利用IDEA工具修改Maven多模塊項目標識包名全過程記錄

    當我們?yōu)榧追椒仗峁┸浖_發(fā)服務時,需要按照甲方的要求去修改軟件的標識,對于Maven項目來說就對應著groupId,一般地寫對方公司的域名,如com.example,接下來通過本文給大家分享IDEA修改Maven多模塊項目標識包名,感興趣的朋友一起看看吧
    2022-09-09
  • SpringBoot中的靜態(tài)資源訪問的實現(xiàn)

    SpringBoot中的靜態(tài)資源訪問的實現(xiàn)

    這篇文章主要介紹了SpringBoot中的靜態(tài)資源訪問的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • Java應該在哪里判斷List是否為空

    Java應該在哪里判斷List是否為空

    在Java中,我們常用List來存儲數據,但是我們怎么判斷它是否成功帶來了我們需要的數據呢?下面這篇文章主要給大家介紹了關于Java應該在哪里判斷List是否為空的相關資料,需要的朋友可以參考下
    2022-02-02
  • Linux中使用shell腳本管理Java應用程序

    Linux中使用shell腳本管理Java應用程序

    在日常開發(fā)和運維工作中,管理基于Java的應用程序是一項基礎且頻繁的任務,本文將通過一個示例腳本,展示如何利用Shell腳本簡化這一流程,實現(xiàn)Java應用的一鍵式啟動、停止與重啟操作,本腳本不僅提升了工作效率,還確保了操作的標準化與可靠性
    2024-06-06

最新評論