這篇文章,是筆者學習hash原始碼的筆記,寫作的過程,利於知識梳理,找到盲區。將會分三篇文章。
這是第一篇,講解hashtable擴容。雖然hashtable已經被concurrenthashmap取代了,但是原始碼簡單,利於我們理解hash的實現方式。
hashtable表結構。陣列+元素節點是單鏈表。
預設陣列長度是11,負載因子是0.75
/**
* constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
*/public
hashtable()
可以手動指定。為什麼hashmap的初始化是16,hashtable是11?原因是hashmap做了優化,後面hashmap篇講解。
hashtable擴容,元素數量達到閾值。閾值的計算。陣列長度 * 負載因子
threshold =
(int
)math.
min(initialcapacity * loadfactor, max_array_size +1)
;
預設的hashtable,當插入第9個元素時候,會擴容。測試**如下
public
class
hashtabletest
private
static object getvalue
(class c1
, object o, string field)
throws nosuchfieldexception, illegalacces***ception }18
:00:55.288
[main] info com.austin.daily.hashmap.hashtabletest -
11
public
static
void
main
(string[
] args)
throws nosuchfieldexception, illegalacces***ception
info com.austin.daily.hashmap.hashtabletest -
23
private
void
addentry
(int hash, k key, v value,
int index)
// creates the new entry.
@suppresswarnings
("unchecked"
) entry
e =(entry
) tab[index]
; tab[index]
=new
entry
<
>
(hash, key, value, e)
; count++
;}
新增entry前,先判斷達到threshold,核心**在rehash()
protected
void
rehash()
//建立乙個新hash陣列
entry,
?>
newmap =
newentry
,?>
[newcapacity]
;//與併發操作鎖有關係,待後續了解
modcount++
;//計算新的閾值
threshold =
(int
)math.
min(newcapacity * loadfactor, max_array_size +1)
;//替換為新的陣列
table = newmap;
//核心中的核心 迴圈old hash表的所有element(element是單鏈表的head)
for(
int i = oldcapacity ; i--
>0;)}}
每行**都有注釋。至此。已經解析完擴容機制。
我注意到。put()方法是頭插法,rehash()也是頭插法。會導致rehash後,插入順序會逆轉。下面是**驗證
@slf4j
public
class
hashtabletest
system.out.
println(""
);system.out.
println
("擴容後");
//擴容後
table.
put(
newkk()
,8);
entries =
(map.entry)
getvalue
(hashtable.
class
, table,
"table");
entry = entries[1]
;while
(entry != null)
}private
static object getvalue
(class c1
, object o, string field)
throws nosuchfieldexception, illegalacces***ception
}classkk}
7,6,
5,4,
3,2,
1,0,
擴容後8,0
,1,2
,3,4
,5,6
,7,process finished with exit code 0
建立類kk,覆蓋hashcode,使得element一定會在陣列索引1。列印的是table[1]的單鏈表元素順序。
觀察擴容前,頭插法,所以在前面;
擴容中,驗證後,果然是和倒置插入順序。8在最前面的原因是,會先處理原有element,再使用頭插法。
Vector和Hashtable原始碼閱讀與理解
vector是執行緒安全的arraylist public synchronized void insertelementat e obj,int index ensurecapacityhelper elementcount 1 system.arraycopy elementdata,index...
SynchronousQueue原始碼閱讀心得
synchronousqueue 簡寫為sq 同步佇列中,讀執行緒與寫執行緒只有相互匹配時才能完成一次完整的讀寫操作。而讀與寫的匹配依賴於transferqueue或transferstack中的transfer sq中重要的資料結構有transferqueue和transferstack,還有qn...
原始碼剖析 Hashtable 原始碼剖析
hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...