日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

阿里二面:聽說過 HashMap 會導致CPU飆升100%嗎?

來源: 責編: 時間:2024-05-24 17:24:11 173觀看
導讀一、問題描述經常有些面試官會問,是否了解過 HashMap 在多線程環(huán)境下使用時可能會發(fā)生死循環(huán),導致服務器 cpu 100% 的線上故障?關于這個問題,很多年前,在淘寶內網里就有很多的程序員發(fā)過這種帖子說一個CPU 被100%了,原因竟

一、問題描述

經常有些面試官會問,是否了解過 HashMap 在多線程環(huán)境下使用時可能會發(fā)生死循環(huán),導致服務器 cpu 100% 的線上故障?BuN28資訊網——每日最新資訊28at.com

關于這個問題,很多年前,在淘寶內網里就有很多的程序員發(fā)過這種帖子說一個CPU 被100%了,原因竟是多線程環(huán)境下使用 HashMap 造成的死循環(huán),并且這個事發(fā)生了很多次。BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

雖然 Java 官方明確表示,在多線程環(huán)境下不推薦使用 HashMap,但是對于這種問題,小編其實也比較意外,如果不是深入的去了解 HashMap,都不知道有這樣的問題。BuN28資訊網——每日最新資訊28at.com

為什么會產生死循環(huán)呢?下面我們來還原一下問題的經過。BuN28資訊網——每日最新資訊28at.com

二、問題重現

在之前的集合系列文章中,我們了解到 HashMap 是一個哈希數組 + 鏈表的數據結構,在實際的程序開發(fā)中,我們經常會使用到 HashMap,如果對 HashMap 不是很了解,大家可以看小編之前寫的《深入淺出分析 HashMap 》一文。BuN28資訊網——每日最新資訊28at.com

HashMap 是一個非線程安全的集合操作類,如果我們的程序操作是單線程的,那么一切都沒問題。當我們的程序是多線程操作 HashMap 類時,那么問題就來了,我們一起來復現一下。BuN28資訊網——每日最新資訊28at.com

測試代碼,如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

使用了4個線程來向 HashMap 中添加元素,可能一次運行不一定有效果,可以反復運行幾次!BuN28資訊網——每日最新資訊28at.com

控制臺輸出結果:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

可以清晰的看到,在遍歷 map 的內容時,已經死循環(huán)了!BuN28資訊網——每日最新資訊28at.com

再來看看,活動監(jiān)視器,結果如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

cpu 的使用率,直接接近 200%!BuN28資訊網——每日最新資訊28at.com

接下來我們去查看下 java 中剛剛運行的 HashThreadTest 類堆棧情況:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

可以看到,HashMap 的擴容操作導致了死循環(huán)!BuN28資訊網——每日最新資訊28at.com

通過測試,我們發(fā)現 HashMap 在多線程環(huán)境下進行操作,的確會產生死循環(huán),并且會導致 CPU 100%!BuN28資訊網——每日最新資訊28at.com

這是為什么呢?我們一起來閱讀一下源碼!BuN28資訊網——每日最新資訊28at.com

三、源碼閱讀

注意注意,小編在進行測試的時候,使用的是 JDK1.7 的版本!BuN28資訊網——每日最新資訊28at.com

如果你使用 JDK1.8 的版本,不好意思,不一定能復現這個問題!因為 JDK1.8 已經修復了這個問題,但是依然不建議在多線程環(huán)境下使用 HashMap!BuN28資訊網——每日最新資訊28at.com

我們繼續(xù)來看看為什么使用 JDK1.7 會出現這個問題!BuN28資訊網——每日最新資訊28at.com

既然是 put 階段造成的數據問題,我們不妨一起來看看 HashMap 的 put 過程!BuN28資訊網——每日最新資訊28at.com

1.HashMap 添加過程

HashMap 的 put 源碼實現如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

接著我們來看看addEntry()方法,將元素插入到數組中,并且檢查容量是否超標,源碼實現如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

上面例子中,我們初始化的時候給定的容量是 2,所以在添加元素時必定會擴容!如果超出閥值,就進行擴容處理,創(chuàng)建一個更大容量的 hash 表,然后把從老的 Hash 表中遷移到新的 Hash 表中,源碼如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

將舊 hash 表中的元素復制到新的 hash 表中,源碼如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

整個 put 過程,大致可以分如下幾個步驟:BuN28資訊網——每日最新資訊28at.com

  • 第一步是通過 key 計算出來的 hash 和 equals 來判斷元素是否存在,如果存在,直接覆蓋;反之,插入;
  • 第二步是將元素插入到 hash 表中,如果不同的元素都在一個 hash 數組下標下,就以鏈表的形式,采用頭插法存儲在 hash 節(jié)點下;
  • 最后就是判斷當前數組容量是否大于擴容閥值,如果大于,就進行擴容處理,然后將舊元素復制到新的數組中;

好了,這個過程基本上沒啥問題。BuN28資訊網——每日最新資訊28at.com

我們再來演示一下擴容中重新計算元素 hash 的過程!BuN28資訊網——每日最新資訊28at.com

2.單線程下擴容元素 hash 過程

假設在單線程環(huán)境下,我們初始化的時候,給定的數組容量是2,分別添加3個元素,內容如下:BuN28資訊網——每日最新資訊28at.com

  • key=3,value=A;
  • key=4,value=B;
  • key=5,value=C;

源碼如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

添加完成之后,數組就會進行擴容處理,擴容后 hash 的容量為原來的2倍,擴容操作流程如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

在單線程環(huán)境下,一切看起來都很正常,擴容過程也相當順利。接下來我們看下并發(fā)情況下的擴容。BuN28資訊網——每日最新資訊28at.com

3.多線程擴容元素 hash 過程

假設我們有兩個線程,來分別添加3個元素。BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

線程二執(zhí)行完添加任務之后,在準備將舊元素遷移到新元素的時候,也就是準備 rehash 時,突然被 CPU 掛起,此時阻塞在如下圖中的第57行,不再往下執(zhí)行!而線程一繼續(xù)執(zhí)行直到擴容完成。BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

2個線程此時的執(zhí)行結果,內容如下:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

接著線程二被喚醒,繼續(xù)回到第57行執(zhí)行。BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

此時注意了,我們來詳細的分析一下這個過程!BuN28資訊網——每日最新資訊28at.com

第一次循環(huán)過程如下:BuN28資訊網——每日最新資訊28at.com

  • 第1步:此時 e 等于{key:3,value:A},next=e.next={key:5,value:C};
  • 第2步:通過 key 重新 hash 計算得到下標 i = 3;
  • 第3步:newTable為局部變量,內容都為null,所以 e.next = newTable[i]=null;
  • 第4步:newTable[i]=e={key:3,value:A};
  • 第5步:e=next={key:5,value:C};

循環(huán)結果如下,e={key:5,value:C},滿足while()循環(huán)條件,接著繼續(xù)!BuN28資訊網——每日最新資訊28at.com

圖片BuN28資訊網——每日最新資訊28at.com

第二次循環(huán)過程如下:BuN28資訊網——每日最新資訊28at.com

  • 第1步:此時 e 等于{key:5,value:C},取最新的鏈表結構,next=e.next={key:3,value:A};
  • 第2步:通過 key 重新 hash 計算得到下標 i = 3;
  • 第3步:在第一次循環(huán)中,newTable[i]已經插入值,所以 e.next = newTable[i]={key:3,value:A};
  • 第4步:newTable[i]=e={key:5,value:C};
  • 第5步:e=next={key:3,value:A};

循環(huán)結果如下,e={key:3,value:A},滿足while()循環(huán)條件,接著繼續(xù)!BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

第三次循環(huán)過程如下:BuN28資訊網——每日最新資訊28at.com

  • 第1步:此時 e 等于{key:3,value:A},取最新的鏈表結構,next=e.next=null;
  • 第2步:通過 key 重新 hash 計算得到下標 i = 3;
  • 第3步:在第二次循環(huán)中,newTable[i]已經插入值,所以 e.next = newTable[i]={key:5,value:C};
  • 第4步:newTable[i]=e={key:3,value:A};
  • 第5步:e=next=null;

循環(huán)結果如下,e=null,while()程序不在循環(huán)!BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

綜合線程1、線程2執(zhí)行結果,最終 hashMap 的存儲結果,如下圖:BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

可以很清晰的看到,鏈表發(fā)生死循環(huán)了!BuN28資訊網——每日最新資訊28at.com

于是,當我們在遍歷 hashMap 鏈表內容的時候,就會出現上文中問題復現的場景,死循環(huán)式的輸出相同的內容,CPU 直接飆到200%了!BuN28資訊網——每日最新資訊28at.com

對于這種問題,當初有人上報到 SUN 公司,但是 SUN 不認為這是一個問題,因為 HashMap 本來就不支持并發(fā)操作!BuN28資訊網——每日最新資訊28at.com

BuN28資訊網——每日最新資訊28at.com

所以,不建議在多線程環(huán)境下使用 HashMap,那如果要在多線程環(huán)境下使用 map 操作類,該怎么辦呢?BuN28資訊網——每日最新資訊28at.com

四、解決辦法

辦法肯定是有的,如果大家想在多線程場景下使用 HashMap,有兩種解決辦法:BuN28資訊網——每日最新資訊28at.com

  • 第一種,推薦使用并發(fā)包中的 ConcurrentHashMap 類,一種使用分段鎖的 hashMap 類,在之后的文章中,咱們也會介紹到它。
  • 另一種,是使用Collections.synchronizedMap(Mao<K,V> map)工具方法,將 HashMap 變成一個線程安全的 map,其實就是對 map 中的方法進行加鎖處理,保證多線程下操作安全!

本文鏈接:http://www.www897cc.com/showinfo-26-90663-0.html阿里二面:聽說過 HashMap 會導致CPU飆升100%嗎?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 敏捷的數據工程實踐

下一篇: 在 WebApi 項目中快速開始使用 RabbitMQ

標簽:
  • 熱門焦點
  • 紅魔電競平板評測:大屏幕硬實力

    前言:三年的疫情因為要上網課的原因激活了平板市場,如今網課的時代已經過去,大家的生活都恢復到了正軌,這也就意味著,真正考驗平板電腦生存的環(huán)境來了。也就是面對著這種殘酷的
  • Raft算法:保障分布式系統(tǒng)共識的穩(wěn)健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可復制、可冗余、可容錯”)的首字母縮寫。Raft算法是一種用于在分布式系統(tǒng)
  • 如何通過Python線程池實現異步編程?

    線程池的概念和基本原理線程池是一種并發(fā)處理機制,它可以在程序啟動時創(chuàng)建一組線程,并將它們置于等待任務的狀態(tài)。當任務到達時,線程池中的某個線程會被喚醒并執(zhí)行任務,執(zhí)行完任
  • 三萬字盤點 Spring 九大核心基礎功能

    大家好,我是三友~~今天來跟大家聊一聊Spring的9大核心基礎功能。話不多說,先上目錄:圖片友情提示,本文過長,建議收藏,嘿嘿嘿!一、資源管理資源管理是Spring的一個核心的基礎功能,不
  • 重估百度丨“晚熟”的百度云,能等到春天嗎?

    &copy;自象限原創(chuàng)作者|程心排版|王喻可2016年7月13日,百度云計算戰(zhàn)略發(fā)布會在北京舉行,宣告著百度智能云的正式啟程。彼時的會場座無虛席,甚至排隊排到了門外,在場的所有人幾乎都
  • ESG的面子與里子

    來源 | 光子星球撰文 | 吳坤諺編輯 | 吳先之三伏大幕拉起,各地高溫預警不絕,但處于厄爾尼諾大&ldquo;烤&rdquo;之下的除了眾生,還有各大企業(yè)發(fā)布的ESG報告。ESG是&ldquo;環(huán)境保
  • 當家的盒馬,加速謀生

    來源 | 價值星球Planet作者 | 歸去來自己&ldquo;當家&rdquo;的盒馬,開始加速謀生了。據盒馬官微消息,盒馬計劃今年開放生鮮供應鏈,將其生鮮商品送往食堂。目前,盒馬在上海已經與
  • Windows 11發(fā)布,微軟一改往常對老機型開放的態(tài)度

    距離 Windows 11 發(fā)布已經過去一周,在過去一周里,很多數碼愛好者圍繞其對 Android 應用的支持、對老機型的升級問題展開了激烈討論。與以往不同的是,在這次大
  • 微軟發(fā)布Windows 11新版 引入全新任務欄狀態(tài)

    近日,微軟發(fā)布了Windows 11新版,而Build 22563更新主要引入了幾周前曝光的平板模式任務欄等,系統(tǒng)更流暢了。更新中,Windows 11加入了專門針對平板優(yōu)化的任務欄
Top 主站蜘蛛池模板: 安西县| 曲阜市| 宜君县| 南漳县| 赤城县| 兴山县| 赤峰市| 安平县| 泸西县| 宣汉县| 信宜市| 托克托县| 遵义市| 金华市| 秦安县| 上虞市| 怀远县| 噶尔县| 鹿泉市| 于都县| 永福县| 大化| 阿拉善盟| 巨鹿县| 本溪市| 哈尔滨市| 阿拉善右旗| 厦门市| 南丰县| 邹城市| 五原县| 广安市| 灵宝市| 廊坊市| 陵水| 萝北县| 京山县| 丹巴县| 阿巴嘎旗| 贞丰县| 巧家县|