1、hashcode相等兩個類一定相等嗎?equals呢?相反呢?
hashCode相等,equals也不一定相等, 兩個類也不一定相等。
原因:hashCode相同,可能是多個鍵,值相同而已,那麼equals也可能不相同;equal相等,那麼必定
是同一個物件,即hashcode必定相同
複製程式碼
2、介紹一下集合框架?
Java中的集合框架的實現是Java容器類相關類庫,容器類有兩種劃分:
(1)、Collection介面:一個包含獨立元素的序列,序列的每一個位置都包含一個獨立的元素,
且各個元素之間是無序的,是可重複的,是可以為null的。
a、繼承了Collection介面的介面有:List、Queue、Set;
b、繼承list介面的有:AbstractList 及LinkedList,常用的ArrayList繼承自AbstractList。
ArrayList是基於陣列實現的,其底層實現為一個長度動態增長的Object[]陣列,
因此其具有訪問快,增刪慢的特點。
c、Queue 不允許隨機訪問其中間的元素,只能從隊首訪問的Collection,且一般來說佇列都
應該是FIFO(先進先出)的。
d、Set是元素不重複的Collection。實現了Set介面的有HashSet、LinkedHashSet、
SortedSet介面繼承了Set介面。
(2)、Map介面:一個每一組資料都是鍵值對的容器,並能夠通過其鍵來查詢其對應值;
a、基於Map介面實現的類有很多,常用的有:TreeMap,HashMap,LinkedHashMap
b、TreeMap儲存key-value對(節點)時,需要根據key對節點進行排序,
可以保證所有的key-value對處於有序狀態
c、HashMap用於快速訪問
d、LinkedHashMap能夠保持元素插入的順序,也提供快速訪問的能力。
複製程式碼
3、hashmap hastable 底層實現什麼區別?hashtable和concurrenthashtable呢?
(1)、HashTable:
底層陣列+連結串列實現,無論key還是value都不能為null,
執行緒安全,實現執行緒安全的方式是在修改資料時synchronized鎖住整個HashTable,效率低,
初始size為11,擴容:newsize = olesize*2+1,
出現hash衝突時採用的是將新元素加入到連結串列的開頭,
定址方式採用的是求餘數:index = (hash & 0x7FFFFFFF) % tab.length
(2)、HashMap:
jdk1.8之前底層陣列+連結串列實現,1.8之後陣列+連結串列+紅黑樹結構
可以儲存null鍵和null值,執行緒不安全
初始size為16,擴容:newsize = oldsize*2,size一定為2的n次冪
擴容針對整個Map,每次擴容時,原來陣列中的元素依次重新計算存放位置,並重新插入
出現hash衝突時,如果連結串列節點數小於8時是將新元素加入到連結串列的末尾
定址方法採用的是位運算按位與:index = hash & (tab.length – 1)
(3)、Concurrenthashtable:
(a)、jdk1.8之前採用Segment + HashEntry的方式進行實現,
預設size為16,Segment在實現上繼承了ReentrantLock,自帶了鎖的功能。
PUT:
當執行put操作時,會進行第一次key的hash來定位Segment的位置,
如果該Segment還沒有初始化,即通過CAS操作進行賦值,
然後進行第二次hash操作,找到相應的HashEntry的位置,
這裡會利用繼承過來的鎖的特性,在將資料插入指定的HashEntry位置時(連結串列的尾端),
會通過繼承ReentrantLock的tryLock()方法嘗試去獲取鎖,
如果獲取成功就直接插入相應的位置,如果已經有執行緒獲取該Segment的鎖,
那當前執行緒會以自旋的方式去繼續的呼叫tryLock()方法去獲取鎖,
超過指定次數(在多處理器環境下,重複次數為64,單處理器重複次數為1)就掛起,
等待喚醒。
SIZE:
先採用不加鎖的方式,連續計算元素的個數,最多計算3次:
如果前後兩次計算結果相同,則說明計算出來的元素個數是準確的;
如果前後兩次計算結果都不同,則給每個Segment進行加鎖,再計算一次元素的個數;
(b)、jdk1.8之後採用Node + CAS + Synchronized來保證併發安全進行實現。
PUT:
1、如果沒有初始化就先呼叫initTable()方法來進行初始化過程
2、如果沒有hash衝突就直接CAS插入
3、如果還在進行擴容操作就先進行擴容
4、如果存在hash衝突,就加鎖來保證執行緒安全,這裡有兩種情況,
一種是連結串列形式就直接遍歷到尾端插入,
一種是紅黑樹就按照紅黑樹結構插入
5、最後一個如果該連結串列的數量大於閾值8,就要先轉換成黑紅樹的結構,
break再一次進入迴圈
6、如果新增成功就呼叫addCount()方法統計size,並且檢查是否需要擴容
SIZE:
使用一個volatile型別的變數baseCount記錄元素的個數,當插入新資料或則刪除數
據時,會通過addCount()方法更新baseCount。
總結:1.7:
Concurrenthashtable儲存結構陣列+連結串列,同步機制採用了”分段鎖”策略,
將map分為N個segment,預設提升16倍,
鍵值對為HashEntry,涉及到的共享變數都使用volatile修飾,volatile可以保證記憶體可見性
1.8:
Concurrenthashtable儲存結構陣列+連結串列+紅黑樹,同步機制採用“CAS + synchronized”,
鍵值對為Node,原始碼中,部分使用sychronizeded關鍵字控制,防止多個執行緒操作。複製程式碼