国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

那些年你啃過的ConcurrentHashMap

開發 前端
JDK1.8這里的紅黑樹,準確的來說是一個TreeBin代理類,它作為紅黑樹的具體實現起存儲作用,而TreeNode是封裝紅黑樹的數據結構,所以你可以理解TreeBin就是封裝TreeNode的一個容器。

前言

我是fancy,一個年紀輕輕bug量就累計到3200個的程序員,同事們都夸我一個人養活了整個測試組。

最近迷上了并發編程。并發這玩意怎么說呢,就是你平時工作用不到,一用就用在面試上。這不,又卷起了并發容器。

那說起并發容器,你一定也知道那幾個,CopyOnWriteArrayList、并發隊列BlockingQueue,等等。但是作為面試的典中典,聊到并發容器就無法繞開ConcurrentHashMap。

由于篇幅原因,這篇文章不會具體解釋那些較為基礎的問題,比如為什么散列表數組的長度一定要是2的n次方等。將更多圍繞并發這?個話題。如有需要,之后會另外講解。

所以本文我們就來深入聊聊這個大廠面試青睞的對象,八股文里的蘭博基尼:ConcurrentHashMap。

圖片

以下的技術點都基于JDK1.8~

基礎回顧

我們都知道,從JDK1.8起,ConcurrentHashMap底層的數據結構就已經從原來的Segment分段鎖變為了數組 + 鏈表 + 紅黑樹的形態。

它是一款并發容器,一款裝數據的容器在并發環境下鐵定就會有各種各樣的問題。你在單線程環境下玩單機,并發環境下就會有別的線程和你搶數據,搶桶位。因此編寫JUC包的大神Doug Lea也都為這些場景一一做了適配,可以說是絕對的并發安全,至少運行了這么多年了也沒遇到什么bug。

紅黑樹

紅黑樹數據結構

JDK1.8這里的紅黑樹,準確的來說是一個TreeBin代理類,它作為紅黑樹的具體實現起存儲作用,而TreeNode是封裝紅黑樹的數據結構,所以你可以理解TreeBin就是封裝TreeNode的一個容器。

紅黑樹在ConcurrentHashMap里面的體現是一個雙向鏈表:

圖片

紅黑樹插入數據

在這里,紅黑樹維護一個字段dir。

在插入數據的時候會獲取節點的hash值,從而與當前節點p的hash值比較,若插入節點的hash小于當前節點,則dir的值為-1,否則為1:

圖片

所以,當dir的值為-1時,就代表插入節點需要插入到當前節點的左子節點或者繼續往左子樹上查找,相反如果dir值為1則向右查找,這里的規則和二叉查找樹的規則是一樣的。

多線程競爭下的讀寫操作

由于讀操作本身就是天然線程安全的。所以多個線程對同一個桶位同時讀并不會有什么問題。

但若是相互競爭的寫操作,就是通過Synchronized鎖的方式來保證某個桶位同一時刻只有一個線程能獲取到資源。

通過源碼可以看到,put()方法的核心是putVal():

圖片

putVal()很長,它主要是通過Synchronized去鎖住每一個節點保證并發的安全性。在這里最為重要的兩點,一是判斷你put進去的這個元素,是處于鏈表還是處于紅黑樹上;二就是判斷當前插入的key是否與鏈表或者紅黑樹上的某個元素一致。如果當前插入key與鏈表當中所有元素的key都不一致時,那么當前的插入操作就追加到鏈表的末尾。否則就替換掉key對應的value。

圖片

擴容原理

在知道擴容原理之前,得知道什么情況會導致擴容。

因此需要知道的兩個重要字段:

  • MIN_TREEIFY_CAPACITY :數組初始長度,默認為64
  • TREEIFY_THRESHOLD :樹化閾值,指定桶位鏈表長度達到8的話,就可能發生樹化操作

線程往桶里面新增每一個元素,都會對鏈表的長度進行判斷,只有元素個數大于閾值MIN_TREEIFY_CAPACITY并且鏈表長度大于8,才會調用treeifyBin()把鏈表轉化為紅黑樹,否則就會進行擴容操作。

這里的擴容,指的就是擴大數組的桶個數,從而裝下更多的元素。

除此之外,擴容還維護了另一重要的字段,sizeCtl:

圖片

通過翻譯,我們可以知道這個字段有三種狀態:

  • sizeCtl < 0:若為-1則起標記作用,告知其它線程此時正在初始化;若為其它的值表示當前table正在擴容
  • sizeCtl = 0:表示創建table數組時還未進行擴容,沒有指定的初始容量
  • sizeCtl > 0:表示當table初始化后下次擴容的觸發條件

字段的值可以轉化為32位的二進制數值,它的高16位表示擴容標識戳,用來標識擴容的范圍,如從長度16擴容到32;低16位表示當前參與擴容的線程數量。

圖片

擴容操作會新建一個長度更大的數組,然后將老數組上的元素全部遷移到新的數組去。

擴容的本質目的是為了減少桶位鏈表的長度,提高查詢效率。因為鏈表的查詢復雜度是O(n),如果鏈表過長就會影響查詢效率。

假設桶位的長度從16擴容到32,說明桶位變多了,那遷移到新數組后就需要有元素去到新的桶位。這就需要通過一些算法將老數組和新數組的元素位置做一個映射。因為擴容后元素有的需要遷移到新的位置,有的還是處于和老數組一樣的位置,只不過是換了一個數組。

如何計算出這個元素遷移后要呆在哪個桶位呢?這里使用了一個按位與的算法。就是將這個桶位key的hash值 & (擴容前數組長度 - 1),若生成的值等于0則不需要遷移,否則就要進行遷移。并且維護兩個變量ln和hn代表是否需要進行位置遷移。然后采用尾插法將元素插入。這就是LastRun機制。

圖片

注:尾插法指的就是后面插入的元素都處于前一個元素的后面

圖片

這里簡單普通的擴容是沒什么問題的,大多數場景都和HashMap的擴容是一樣的。

問題就在于當前是處于并發環境的,而擴容也需要時間。

正在擴容 && 有多個線程正在競爭

所以,比較復雜的場景來了。若是桶位正在擴容,且有多個線程正在競爭讀寫咋辦?厚禮謝

沒關系,我們依然分情況來討論。

擴容期間的讀操作

如果擴容期間,有線程進行元素的讀取,比如你去get()某個key的value,那讀不讀的到呢?

答案是可以。但是前提是你這個節點已經遷移結束,如果你是一個正在擴容遷移的節點,那就訪問不到。

具體的操作,就是去調用find()。

當一個桶位要進行數據遷移,就會往這個桶位上放置一個ForwardingNode節點。除此之外還需要去標識這個節點是正在遷移還是已經遷移結束了的;

在這里我們統稱遷移前的桶位節點叫老節點,遷移后的桶位節點叫新節點。當其中某一個節點遷移完成后,就會在老節點上添加一個fwd引用,它指向新節點的地址。

所以當某個線程訪問了這個節點,看到它上面存在fwd引用,就說明當前table正在擴容,那么就會根據這個引用上的newtable字段去新數組的對應桶位上找到數據然后返回。

圖片

擴容期間的寫操作

寫操作相較于讀操作會更加復雜一點,原因就是讀操作只需要獲取對應數據返回就行了,而寫操作還要修改數據,所以當一個寫線程來修改數據剛好碰到容器處于擴容期間,那么它還要協助容器進行擴容。

具體的擴容操作依然還要分情況,假如訪問的桶位數據還沒有被遷移走的話,那就直接競爭鎖,然后在老節點上進行操作就行。

但是假如線程修改的節點正好是一個fwd節點,說明當前節點正處于擴容操作,那么為了節約線程數并且快速完成任務,當前線程就會進行協助擴容。如果有多個線程進行同時寫,那么它們都會調用helpTransfer()進行協助擴容。

這里協助擴容的方式就是拿到一個擴容標識戳,這個標識戳的作用就是用來標識擴大的容量大小。因為每個線程都是獨立的嘛,互不通信,但是它們要做的事情是相同的,就是將桶位擴大相同的值,所以它們就必須拿到這個相同的標識戳,只有標識戳一致才會進行擴容。

假設一個容器從16個桶位擴容到32個桶位,有線程A、B兩個線程。

若A觸發了擴容的機制,那么線程A就會進行擴容,此時線程B也來進行寫操作,發現正在擴容就會進入到協助擴容的步驟中去。

所以線程A和線程B共同負責桶位的擴容。

一個線程負責擴容的桶位個數,是根據CPU核心數來算的。最少是16個,也就是一個線程最少要負責16個元素的擴容:

我們在上面有提過,sizeCtl轉化為32位后,它的低16位是表示當前參與擴容的線程數量。所以當A線程觸發了擴容之后,它就會將sizeCtl低16位的最后一位值+1,表示擴容線程多了一位,當它退出擴容時又會將最后一位的值-1,表示擴容線程少了一位,就這樣各個線程共同維護這個字段。

圖片

所以你一定會好奇了:那我要是最后一個退出擴容的線程要怎么維護啊?是的,最后一個線程還有一些別的事情要做。當某一個線程完成任務后去判斷sizeCtl的值得時候,發現它的低16位只剩下最后一位是1,再減下去就是0了,那就代表它是最后一個退出擴容的線程。此時它還需要去檢查一遍老的table數組,判斷是否還有遺漏的slot沒有遷移。具體的操作就是去輪詢檢查是否還留有fwd節點,如果沒有的話代表遷移完成,如果有的話還需要繼續將它遷移到新的桶位。

由于源碼非常長,所以我們就不貼全部源碼了,通過流程圖的方式來幫助大家理解這個擴容期間的操作:

圖片

總結

有的童鞋在看Juc這一塊的時候會去背誦源碼,將方法的調用鏈都講的頭頭是道,我認為沒有必要,相反面試官可能會覺得你過于抽象,背的這么清楚。并發的核心在于如何用手段去解決可能遇到的安全問題,并且讓它更高效點,面試的目的也是為了體現你思維能力。

責任編輯:武曉燕 來源: fancyJava
相關推薦

2025-06-03 01:45:00

2018-08-13 17:41:13

機房

2021-05-05 14:00:25

QQ手機QQ移動應用

2012-05-31 09:53:38

IT風云15年

2016-01-12 09:49:35

AndroidiOSWindows Pho

2021-04-07 22:25:05

手機LG諾基亞

2015-09-22 10:59:45

iOS 9功能

2015-06-19 13:54:49

2015-01-06 14:39:41

云計算云存儲數據遷移

2019-10-24 08:00:00

JSON工具前端

2015-07-23 09:30:43

爛代碼程序員

2015-05-26 09:57:33

2018-10-24 11:07:11

互聯網開放手機

2021-01-16 16:14:10

QQ新浪UC百度

2016-12-26 13:03:13

大數據80篇爆款文章技術

2015-01-14 12:12:38

小米

2017-11-03 13:43:24

云計算Saas信息化

2017-06-21 08:39:20

SparkScalaHDFS

2021-05-06 08:28:04

mq中間件消息中間件

2014-05-30 10:23:15

樂跑手環智能手環運動手環
點贊
收藏

51CTO技術棧公眾號

久久久亚洲精华液精华液精华液| 国产999精品视频| 亚洲一区二区免费看| 一区二区三区不卡在线视频| 国产精品高精视频免费| 亚洲精品视频观看| 欧美在线电影| 日本在线视频1区| 亚洲综合在线做性| 色悠悠亚洲一区二区| 欧美在线免费| 久cao在线| 欧美日韩一区二 | 黄a在线观看| 日韩欧美一区二区三区四区 | 国内欧美视频一区二区| 亚洲精品555| 无码人妻丰满熟妇区毛片18| 国内外成人免费激情在线视频网站| 亚洲欧洲精品成人久久奇米网| 精品免费视频| se在线电影| 一区二区三视频| 两个人的视频www国产精品| 国产精品伦一区| 成人女性视频| 在线看av的网址| 久久久久久久久久久久久国产| 欧美成人sm免费视频| 亚洲日本丝袜连裤袜办公室| 欧美在线视屏| 超碰在线99| 欧美精品一区免费| 国产精品视频xxxx| 日韩欧美中文字幕公布| 丰满放荡岳乱妇91ww| 天天躁日日躁狠狠躁欧美| 免费在线稳定资源站| 天天干天天操天天干天天操| 国产做受高潮69| 在线观看日韩高清av| 国内成人精品2018免费看| 麻豆精品av| 好了av在线| 男人舔女人下面高潮视频| 91青草视频久久| 亚洲女人天堂av| 亚洲欧美在线高清| 亚洲综合精品| 国产一区二区久久久久| 国产精品视频一区二区图片 | 男女视频在线观看| 男人的天堂成人| 日本在线精品视频| 日韩一区二区在线看| 久久天堂av综合合色蜜桃网| 你懂的国产精品永久在线| xx欧美xxx| 又黄又爽在线免费观看| 欧美h视频在线观看| 国产精品久久中文| 亚洲女在线观看| 亚洲成人av福利| 岛国精品在线播放| 久久久久久久久久久妇女 | 国产伦视频一区二区三区| 色黄久久久久久| 日本黄色一区二区| 久久久一区二区三区捆绑**| 亚洲伦伦在线| 精品福利一区| 激情国产在线| 欧美白人做受xxxx视频| 99热成人精品热久久66| 欧美日韩在线高清| 国产精品人成电影| 日韩亚洲欧美中文在线| 91精品国产免费久久综合| 亚洲精品一二三| av成人免费在线观看| 亚洲小说欧美另类社区| 老牛国内精品亚洲成av人片| 在线黄色的网站| 国产精品久久久久一区二区国产 | 国产欧美一区二区色老头| 在线播放一区二区精品视频| 黄页网站在线观看免费| 宅男深夜国产| 欧美私人情侣网站| 一区二区三区电影| 国产不卡一区二区三区在线观看| 欧美极品少妇xxxxⅹ免费视频| 亚洲成人网在线观看| 欧美午夜片在线观看| 亚洲欧美日韩中文字幕一区二区三区 | 精品一区二区电影| 欧美午夜宅男影院| 亚洲人成网站精品片在线观看| 成人午夜视频网站| 夜夜爽av福利精品导航| 欧美特黄一级大片| 成人资源在线播放| 伊人久久一区| 日韩成人影音| 国产99在线观看| 最爽无遮挡行房视频在线| 欧美少妇另类| 在线免费黄色毛片| 日本18视频网站| 四虎国产成人永久精品免费| 日韩av资源在线| 欧美 丝袜 自拍 制服 另类| 欧美日韩一区二区三区在线视频| 3d精品h动漫啪啪一区二区| 国产精品igao视频| 欧美一性一乱一交一视频| 欧美激情精品久久久久久变态| 伊人久久五月天| 亚洲欧美国产va在线影院| 精品免费一区二区三区| 欧美一区二区在线免费播放| 欧美体内she精视频| 一本大道久久a久久精二百| 亚洲成人av在线电影| 亚洲一区二区三区精品在线| 国产精品盗摄一区二区三区| 国产欧美一区二区精品忘忧草| 91在线免费视频观看| 91欧美一区二区| 久久久一区二区| 久久久国产综合精品女国产盗摄| 国产91精品欧美| 国产成人精品亚洲777人妖| 国产一区二区日韩精品| 国产精品资源在线观看| 国产一区二区三区精品欧美日韩一区二区三区 | 国产美女精品视频| 青青久久aⅴ北条麻妃| 午夜精品蜜臀一区二区三区免费| 欧美精品在线观看91| 久久乐国产精品| 欧美资源在线观看| 国产精品美女久久久久久免费| 国产精品稀缺呦系列在线| 成人免费网站在线看| www.久久草| 欧美精品123| 一道本在线观看视频| 欧美日韩成人免费视频| 久久久久久久久久福利| 成人影院一区二区三区| 超碰在线12| 久久精品国产亚洲a∨麻豆| 999国产在线视频| 青草在线视频在线观看| 在线高清av| 秋霞午夜一区二区三区视频| 老司机精品视频在线播放| 精品国产91久久久久久浪潮蜜月| 97精品国产| 国产精品亚洲产品| 日本sm残虐另类| 不卡的av网站| 亚洲激情图片小说视频| 欧美在线一二三| 日韩一区二区三区av| 亚洲最新av在线| 国内外成人免费激情在线视频网站| 日本亚洲欧美成人| 成人在线视频网| 天堂av一区二区| 亚洲 欧美 日韩 国产综合 在线| 色www免费视频| 邻居大乳一区二区三区| 国产丝袜在线播放| 久久9999免费视频| 色偷偷综合网| 日本va欧美va欧美va精品| 91网站在线观看视频| 亚洲线精品一区二区三区八戒| 欧美美女一区二区在线观看| 国产一区二区免费| 日本亚洲欧洲色| 免费在线观看91| www.com毛片| 色视频免费在线观看| 免费一二一二在线视频| 精品国产一区二区三区成人影院 | 婷婷成人基地| 免费成人在线网站| 91久色porny| 一本色道久久综合狠狠躁的推荐| 亚洲国产精品久久久久| 国内精品久久久久久影视8| 国产精品福利视频| www国产精品内射老熟女| 在线免费观看你懂的| 阿v视频在线| 精品人人人人| 久久狠狠婷婷|