背景:hashmap面試基礎必考內容,須要深刻了解,並學習其中的相關原理。此處還要明白1.7和1.8不通版本的優化點。html
鑑於JDK1.8作了多方面的優化,整體性能優於JDK1.7,下面咱們從兩個方面用例子證實這一點(在hash均勻和不均勻的狀況下性能都有明顯的提高)面試
無論增長、刪除、查找鍵值對,定位到哈希桶數組的位置都是很關鍵的第一步。前面說過HashMap的數據結構是數組和鏈表的結合,因此咱們固然但願這個HashMap裏面的元素位置儘可能分佈均勻些,儘可能使得每一個位置上的元素數量只有一個,那麼當咱們用hash算法求得這個位置的時候,立刻就能夠知道對應位置的元素就是咱們要的,不用遍歷鏈表,大大優化了查詢的效率。HashMap定位數組索引位置,直接決定了hash方法的離散性能。先看看源碼的實現(方法一+方法二):算法
方法一: static final int hash(Object key) { //jdk1.8 & jdk1.7 int h; // h = key.hashCode() 爲第一步 取hashCode值 // h ^ (h >>> 16) 爲第二步 高位參與運算 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 方法二: static int indexFor(int h, int length) { //jdk1.7的源碼,jdk1.8沒有這個方法,可是實現原理同樣的 return h & (length-1); //第三步 取模運算 }
這裏的Hash算法本質上就是三步:取key的hashCode值、高位運算、取模運算。數組
對於任意給定的對象,只要它的hashCode()返回值相同,那麼程序調用方法一所計算獲得的Hash碼值老是相同的。咱們首先想到的就是把hash值對數組長度取模運算,這樣一來,元素的分佈相對來講是比較均勻的。可是,模運算的消耗仍是比較大的,在HashMap中是這樣作的:調用方法二來計算該對象應該保存在table數組的哪一個索引處。安全
這個方法很是巧妙,它經過h & (table.length -1)來獲得該對象的保存位,而HashMap底層數組的長度老是2的n次方,這是HashMap在速度上的優化。當length老是2的n次方時,h& (length-1)運算等價於對length取模,也就是h%length,可是&比%具備更高的效率。數據結構
在JDK1.8的實現中,優化了高位運算的算法,經過hashCode()的高16位異或低16位實現的:(h = k.hashCode()) ^ (h >>> 16),主要是從速度、功效、質量來考慮的,這麼作能夠在數組table的length比較小的時候,也能保證考慮到高低Bit都參與到Hash的計算中,同時不會有太大的開銷。多線程
Java源碼分析:HashMap 1.8 相對於1.7 到底更新了什麼?源碼分析
ps超詳細的 太牛逼了 好好讀讀post
1.8不會出現1.7的多線程環形鏈死循環狀況,可是還不是線程安全的,由於沒有同步鎖。
jdk1.8與1.7之間 hashmap的不一樣,優化點!!
全部處理的根本目的,都是爲了提升 存儲key-value
的數組下標位置 的隨機性 & 分佈均勻性,儘可能避免出現hash值衝突。即:對於不一樣key
,存儲的數組下標位置要儘量不同
JDK 1.8
的優化目的主要是:減小 Hash
衝突 & 提升哈希表的存、取效率