HashMap的初始化
int DEFAULT_INITIAL_CAPACITY = 16:默認(rèn)的初始容量為16
int MAXIMUM_CAPACITY = 1 << 30:最大的容量為 2 ^ 30
float DEFAULT_LOAD_FACTOR = 0.75f:默認(rèn)的加載因子為 0.75f
Entry< K,V>[] table:Entry類型的數(shù)組凛篙,HashMap用這個(gè)來維護(hù)內(nèi)部的數(shù)據(jù)結(jié)構(gòu)昙衅,它的長度由容量決定
int size:HashMap的大小
int threshold:HashMap的極限容量另凌,擴(kuò)容臨界點(diǎn)(容量和加載因子的乘積)
每次新建一個(gè)HashMap時(shí)糕档,都會初始化一個(gè)table數(shù)組境析。table數(shù)組的元素為Entry節(jié)點(diǎn)
HashMap如何解決沖突
背景
散列表要解決的一個(gè)問題就是散列值的沖突問題义矛,通常是兩種方法:鏈表法和開放地址法妨托。
鏈表法就是將相同hash值的對象組織成一個(gè)鏈表放在hash值對應(yīng)的槽位缸榛;
開放地址法是通過一個(gè)探測算法,當(dāng)某個(gè)槽位已經(jīng)被占據(jù)的情況下繼續(xù)查找下一個(gè)可以使用的槽位
HashMap里面沒有出現(xiàn)hash沖突時(shí)兰伤,沒有形成單鏈表時(shí)内颗,hashmap查找元素很快,get()方法能夠直接定位到元素,但是出現(xiàn)單鏈表后敦腔,單個(gè)bucket 里存儲的不是一個(gè) Entry均澳,而是一個(gè) Entry 鏈,系統(tǒng)只能必須按順序遍歷每個(gè) Entry符衔,直到找到想搜索的 Entry 為止——如果恰好要搜索的 Entry 位于該 Entry 鏈的最末端(該 Entry 是最早放入該 bucket 中)找前,那系統(tǒng)必須循環(huán)到最后才能找到該元素.
創(chuàng)建 HashMap 時(shí),有一個(gè)默認(rèn)的負(fù)載因子(load factor)判族,其默認(rèn)值為 0.75躺盛,這是時(shí)間和空間成本上一種折衷:增大負(fù)載因子可以減少 Hash 表(就是那個(gè) Entry 數(shù)組)所占用的內(nèi)存空間,但會增加查詢數(shù)據(jù)的時(shí)間開銷五嫂,而查詢是最頻繁的的操作(HashMap 的 get() 與 put() 方法都要用到查詢)颗品;減小負(fù)載因子會提高數(shù)據(jù)查詢的性能肯尺,但會增加 Hash 表所占用的內(nèi)存空間
線程不安全的HashMap
因?yàn)槎嗑€程環(huán)境下,使用Hashmap進(jìn)行put操作會引起死循環(huán)躯枢,導(dǎo)致CPU利用率接近100%则吟,所以在并發(fā)情況下不能使用HashMap
final HashMap<String, String> map = new HashMap<String, String>(2);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
map.put(UUID.randomUUID().toString(), "");
}
}, "ftf" + i).start();
}
}
}, "ftf");
t.start();
t.join();
效率低下的HashTable容器
HashTable容器使用synchronized來保證線程安全,但在線程競爭激烈的情況下HashTable的效率非常低下锄蹂。因?yàn)楫?dāng)一個(gè)線程訪問HashTable的同步方法時(shí)氓仲,其他線程訪問HashTable的同步方法時(shí),可能會進(jìn)入阻塞或輪詢狀態(tài)得糜。如線程1使用put進(jìn)行添加元素敬扛,線程2不但不能使用put方法添加元素,并且也不能使用get方法來獲取元素朝抖,所以競爭越激烈效率越低啥箭。
ConcurrentHashMap的鎖分段技術(shù)
HashTable容器在競爭激烈的并發(fā)環(huán)境下表現(xiàn)出效率低下的原因,是因?yàn)樗性L問HashTable的線程都必須競爭同一把鎖治宣,那假如容器里有多把鎖急侥,每一把鎖用于鎖容器其中一部分?jǐn)?shù)據(jù),那么當(dāng)多線程訪問容器里不同數(shù)據(jù)段的數(shù)據(jù)時(shí)侮邀,線程間就不會存在鎖競爭坏怪,從而可以有效的提高并發(fā)訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術(shù)绊茧,首先將數(shù)據(jù)分成一段一段的存儲铝宵,然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問其中一個(gè)段數(shù)據(jù)的時(shí)候华畏,其他段的數(shù)據(jù)也能被其他線程訪問鹏秋。