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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理

發布時間:2025/3/19 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

HashMap底層實現原理,紅黑樹,B+樹,B樹的結構原理,volatile關鍵字,CAS(比較與交換)實現原理

首先HashMap是Map的一個實現類,而Map存儲形式是鍵值對(key,value)的。可以看成是一個一個的Entry。Entry所存放的位置是由key來決定的。

Map中的key是無序的且不可重復的,所有的key可以看成是一個set集合,如果出現Map中的key如果是自定義類的對象,則必須重寫hashCode和equals方法,因為如果不重寫,使用的是Object類中的hashCode和equals方法,比較的是內存地址值不是比內容。

Map中的value是無序的可重復的,所有的value可以看成是Collection集合,Map中的value如果是自定義類的對象必須重寫equals方法。

至于要重寫hashCode和equals分別做什么用,拿hashMap底層原理來說:

當我們向HashMap中存放一個元素(k1,v1),先根據k1的hashCode方法來決定在數組中存放的位置。

如果這個位置沒有其它元素,將(k1,v1)直接放入Node類型的數組中,這個數組初始化容量是16,默認的加載因子是0.75,也就是當元素加到12的時候,底層會進行擴容,擴容為原來的2倍。如果該位置已經有其它元素(k2,v2),那就調用k1的equals方法和k2進行比較二個元素是否相同,如果結果為true,說明二個元素是一樣的,用v1替換v2,如果返回值為false,二個元素不一樣,就用鏈表的形式將(k1,v1)存放。

不過當鏈表中的數據較多時,查詢的效率會下降,所以在JDK1.8版本后做了一個升級,就是當鏈表中的元素達到8時,會將鏈表替換成紅黑樹,來提高查找效率。因為對于搜索,插入,刪除操作多的情況下,使用紅黑樹的效率要高一些。

原因是因為紅黑樹是一種特殊的二叉查找樹,二叉查找樹所有節點的左子樹都小于該節點,所有節點的右子樹都大于該節點,就可以通過大小比較關系來進行快速的檢索。

在紅黑樹上插入或者刪除一個節點之后,紅黑樹就發生了變化,可能不滿足紅黑樹的5條性質,也就不再是一顆紅黑樹了,而是一顆普通的樹,可以通過左旋和右旋,使這顆樹重新成為紅黑樹。紅黑樹的5條性質(根節點是黑色,每個節點是黑色或者是紅色,每個葉子節點是黑色,如果一個節點是紅色它的子節點必須是黑色的,從一個節點到該節點的子孫外部節點的所有路徑上包含相同數目的黑點)

而且像這種二叉樹結構比較常見的使用場景是Mysql二種引擎的索引,Myisam使用的是B樹,InnoDB使用的是B+樹。

首先B樹它的每個節點都是Key.value的二元組,它的key都是從左到右遞增的排序,value中存儲數據。這種模式在讀取數據方面的性能很高,因為有單獨的索引文件,Myisam 的存儲文件有三個.frm是表的結構文件,.MYD是數據文件,.MYI是索引文件。不過Myisam 也有些缺點它只支持表級鎖,不支持行級鎖也不支持事務,外鍵等,所以一般用于大數據存儲。

然后是InnoDB,它的存儲文件相比Myisam少一個索引文件,它是以 ID 為索引的數據存儲,數據現在都被存在了葉子結點,索引在非葉結點上。而這些節點分散在索引頁上。在InnoDB里,每個頁默認16KB,假設索引的是8B的long型數據,每個key后有個頁號4B,還有6B的其他數據,那么每個頁的扇出系數為16KB/(8B+4B+6B)≈1000,即每個頁可以索引1000個key。在高度h=3時,s=1000^3=10億!!也就是說,InnoDB通過三次索引頁的I/O,即可索引10億的key,而非葉節點這一行存儲的索引,數量就多了,I/O的次數就少了。而Myisam在每個節點都存儲數據和索引,這樣就減少了每頁存儲的索引數量。而且InnoDB它還支持行級,表級鎖,也支持事務,外鍵.

另外對于HashMap實際使用過程中還是會出現一些線程安全問題:

HashMap是線程不安全的,在多線程環境下,使用Hashmap進行put操作會引起死循環,導致CPU利用率接近100%,而且會拋出并發修改異常,導致原因是并發爭取線程資源,修改數據導致的,一個線程正在寫,一個線程過來爭搶,導致線程寫的過程被其他線程打斷,導致數據不一致。

HashTable是線程安全的,只不過實現代價卻太大了,簡單粗暴,get/put所有相關操作都是synchronized的,這相當于給整個哈希表加了一把大鎖。多線程訪問時候,只要有一個線程訪問或操作該對象,那其他線程只能阻塞,相當于將所有的操作串行化,在競爭激烈的并發場景中性能就會非常差。

為了應對hashmap在并發環境下不安全問題可以使用,ConcurrentHashMap大量的利用了volatile,CAS等技術來減少鎖競爭對于性能的影響。

在JDK1.7版本中ConcurrentHashMap避免了對全局加鎖,改成了局部加鎖(分段鎖),分段鎖技術,將數據分成一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據的時候,其他段的數據也能被其他線程訪問,能夠實現真正的并發訪問。不過這種結構的帶來的副作用是Hash的過程要比普通的HashMap要長。

所以在JDK1.8版本中CurrentHashMap內部中的value使用volatile修飾,保證并發的可見性以及禁止指令重排,只不過volatile不保證原子性,使用為了確保原子性,采用CAS(比較交換)這種樂觀鎖來解決。

CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。

如果內存地址里面的值和A的值是一樣的,那么就將內存里面的值更新成B。CAS是通過無限循環來獲取數據的,若果在第一輪循環中,a線程獲取地址里面的值被b線程修改了,那么a線程需要自旋,到下次循環才有可能機會執行。

volatile有三個特性:可見性,不保證原子性,禁止指令重排。

可見性:線程1從主內存中拿數據1到自己的線程工作空間進行操作(假設是加1)這個時候數據1已經改為數據2了,將數據2寫回主內存時通知其他線程(線程2,線程3),主內存中的數據1已改為數據2了,讓其他線程重新拿新的數據(數據2)。

不保證原子性:線程1從主內存中拿了一個值為1的數據到自己的工作空間里面進行加1的操作,值變為2,寫回主內存,然后還沒有來得及通知其他線程,線程1就被線程2搶占了,CPU分配,線程1被掛起,線程2還是拿著原來主內存中的數據值為1進行加1,值變成2,寫回主內存,將主內存值為2的替換成2,這時線程1的通知到了,線程2重新去主內存拿值為2的數據。

禁止指令重排:首先指令重排是程序執行的時候不總是從上往下執行的,就像高考答題,可以先做容易的題目再做難的,這時做題的順序就不是從上往下了。禁止指令重排就杜絕了這種情況。

總結

以上是生活随笔為你收集整理的HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。