這次疫情讓幾個關係很好的前同事都跳槽了,基本都面了大廠 阿里系、騰訊系、華爲、平安等也都拿到了各自滿意的offer,居安思危的我將他們經歷的面試題收集整理然後根據自身情況解答覆習。每週最少兩大題(包含擴展問題)分享出來,大家一起學習。
CurrentHashMap、HashMap、HashTable的區別
大方向區別爲:
HashMap 線程不安全的 ,HashTable 線程安全的任一時間只有一個線程能寫Hashtable,CurrentHashMap線程安全的,引入分段鎖。
HashMap 詳解
HashMap 結構
- JDK1.8以前 數組+單向鏈表
- JDK1.8以後 數組+單向鏈表+紅黑樹
爲什麼要用紅黑樹
即使負載因子和Hash算法設計的再合理,也免不了會出現拉鍊過長的情況,一旦出現拉鍊過長,則會嚴重影響HashMap的性能。於是,在JDK1.8版本中,對數據結構做了進一步的優化,引入了紅黑樹。而當鏈表長度太長(默認超過8)時,鏈表就轉換爲紅黑樹,利用紅黑樹快速增刪改查的特點提高HashMap的性能,長度小於6時紅黑樹轉爲鏈表。
課外習題:紅黑樹是啥?
紅黑樹是一個平衡二叉樹
通過旋轉和變色來保持平衡,擁有如下特性
- 每個節點要麼是黑色,要麼是紅色。
- 根節點是黑色。
- 每個葉子節點(NIL)是黑色。
- 每個紅色結點的兩個子結點一定都是黑色。
- 任意一結點到每個葉子結點的路徑都包含數量相同的黑結點。
HashMap put()方法實現流程
哈希值計算方式
hash函數是先拿到通過key 的hashcode,是32位的int值,然後讓hashcode的高16位和低16位進行異或操作。這個也叫擾動函數,這麼設計有三點原因:
- 一定要儘可能降低hash碰撞,越分散越好;
- 算法一定要儘可能高效,因爲這是高頻操作, 因此採用位運算;
- 混合原始哈希碼的高位和低位,以此來加大低位的隨機性,減少碰撞
什麼樣的對象可以成爲HashMap 的Key值
重寫過hashCode和equals的對象,才能做爲key。
如何得到一個線程安全的HashMap?
Collections.synchronizedMap(Map)
Collections 類提供了一個Map接口的實現的內部類 將所有方法都加了synchronized
HashTable簡介
HashTable是直接在操作方法上加synchronized關鍵字,鎖住整個數組。從而達到線程安全。無論key還是value都不能爲null
ConcurrentHashMap簡介
分段的數組+鏈表實現
ConcurrentHashMap允許多個修改操作併發進行,其關鍵在於使用了鎖分離技術
有些方法需要跨段,比如size()和containsValue(),它們可能需要鎖定整個表而而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢後,又按順序釋放所有段的鎖。
Map延伸題
有序的map
HashMap、HashTable、ConcurrentHashMap都是根據hash值隨機插入,是無序的,
LinkedHashMap 是有序的因爲LinkedHashMap內部維護了一個單鏈表,有頭尾節點,可以實現按插入的順序或訪問順序排序。
TreeMap是按照Key的自然順序或者Comprator(實現Comprator接口)的順序進行排序,內部是通過紅黑樹來實現。