問題:為什么ConcurrentHashMap每次擴(kuò)容的時候擴(kuò)大一倍良拼?
答案:通過位運(yùn)算,代替模運(yùn)算充边,速度更快
眾所周知:key要通過哈希函數(shù)變成一個數(shù)字庸推,然后存放在哈希表對應(yīng)的位置中。存放會涉及到一些哈希沖突的時候浇冰,就通過鏈表贬媒,或者平衡二叉樹,將新key放在舊key后面湖饱。
例子:"name"(key)? ? "zhangsan"(value) 掖蛤,當(dāng)前的哈希表容量是8
1.????通過java的hashCode()?函數(shù)可以計(jì)算出哈希碼
2.? ? “name”字符串的哈希碼是3373707(十進(jìn)制),1100110111101010001011(二進(jìn)制)
3.? ? 將1100110111101010001011與哈希表的容量8-1 = 7做一次與運(yùn)算(&)
? ? ? ? 結(jié)果顯示是011也就是十進(jìn)制的3
4.? ? 將key放入大小為8的哈希表中
5.? ? 其他的key:
? ? ? ? “age”? ? ? ? ?96511 ? ?10111100011111111? ?最后三位是111?與 7(111)做與運(yùn)算得到111井厌,放入第七個空格中
? ? ? ? “email”??96619420????101110000100100101110011100蚓庭,做與運(yùn)算,放入100位置仅仆,也就是4號空格中
? ? ? ? "phone"????194811?????101111100011110011器赞,與7做與運(yùn)算,放入3號空格墓拜,哈希沖突港柜,以鏈表形式放到name后面
6.? ? 當(dāng)我們要擴(kuò)展哈希表為16個空格的時候,16-1=15 咳榜,15的二進(jìn)制是1111
? ? ? ? 這個時候我們再比較一下
????????“name”的哈希碼1100110111101010001011
? ? ? ? “phone”的哈希碼101111100011110011
? ? ? ? 當(dāng)他們與15(1111)做與運(yùn)算的時候夏醉,和與 7(111)做與運(yùn)算的時候有什么不同?
? ? ? ? “name”:
? ? ? ?“phone”
? ? 這時候涌韩,name的結(jié)果是(11)1011畔柔,“phone”結(jié)果是(3)0011
? ? 發(fā)現(xiàn):name因?yàn)楦咭晃皇?,所以應(yīng)該離開到11號空格臣樱,phone因?yàn)楦咭晃皇?靶擦,還會留在3號空格中!雇毫!
? ? 這就是擴(kuò)大一倍帶來計(jì)算上的簡便P丁!
? ? ? ? ? ? 當(dāng)初容量是8棚放,8-1=7枚粘,7的二進(jìn)制是111
? ? ? ? ? ? 現(xiàn)在容量是16,16-1=15席吴,15的二進(jìn)制是1111
? ? ? ? ? ? 因?yàn)樗麄兌际侨珵?的形態(tài)赌结,而擴(kuò)大一倍后只是高位加了一個1捞蛋,所以會留有大概一半的key在原來的空格,而有一半的key到相同的別的空格中柬姚,比如都是從3號位置到了11號位置中拟杉,這樣也便于復(fù)制。
? ? ? ? ? ? 通過位運(yùn)算量承,代替了模運(yùn)算搬设!