Hashtable和HashMap都實現(xiàn)了Map接口想虎,但是Hashtable的實現(xiàn)是基于Dictionary抽象類的。
hashmap( 效率高于hashTable 叛拷、非線程安全? )
如果需要滿足線程安全舌厨,可以用?Collections的synchronizedMap方法使HashMap具有線程安全的能力,或者使用ConcurrentHashMap忿薇。
·底層數(shù)組+鏈表實現(xiàn)裙椭,可以存儲null鍵和null值
hashtable(?線程安全、效率低下
)
HashTable?只有一把鎖署浩,當一個線程訪問HashTable的同步方法時骇陈,會將整張table?鎖住,當其他線程也想訪問HashTable?同步方法時瑰抵,就會進入阻塞或輪詢狀態(tài)你雌。也就是確保同一時間只有一個線程對同步方法的占用,避免多個線程同時對數(shù)據(jù)的修改,確保線程的安全性婿崭。但HashTable?對get拨拓,put,remove?方法都使用了同步操作氓栈,這就造成如果兩個線程都只想使用get?方法去讀取數(shù)據(jù)時渣磷,因為一個線程先到進行了鎖操作,另一個線程就不得不等待授瘦,這樣必然導致效率低下醋界,而且競爭越激烈,效率越低下提完。
·?底層數(shù)組+鏈表實現(xiàn)形纺,無論key還是value都不能為null
ConcurrentHashMap(加入了分段鎖,并發(fā)又安全)
在hashMap?的基礎上徒欣,ConcurrentHashMap?將數(shù)據(jù)分為多個segment(默認16個)逐样,然后每次操作對一個segment?加鎖,HashTable?在競爭激烈的并發(fā)環(huán)境下表現(xiàn)出效率低下的原因是打肝,由于所有訪問HashTable的線程都必須競爭同一把鎖脂新,而ConcurrentHashMap?將數(shù)據(jù)分到多個segment?中(默認16,此時效率提升16倍)粗梭,每個segment?都有一個自己的鎖争便,只要多個線程訪問的不是同一個segment?就沒有鎖爭用,就沒有堵塞断医,也就是允許16個線程并發(fā)的更新而盡量沒有鎖爭用滞乙。
·底層采用分段的數(shù)組+鏈表實現(xiàn)
弱一致性的體現(xiàn): get 操作是弱一致、 clear 方法是弱一致的 ?迭代器弱一致的
1.ConcurrentHashMap#get():為 get 操作幾乎所有時候都是一個無鎖操作孩锡,使得同一個
Segment 實例上的 put 和 get 可以同時進行酷宵,這就是 get 操作是弱一致的根本原因。
2.ConcurrentHashMap#clear():沒有全局的鎖躬窜,在清除完一個 segment 之后浇垦,正在清理下一個segment 的時候,已經清理的 segment 可能又被加入了數(shù)據(jù)荣挨,因此 clear返回的時候ConcurrentHashMap 中是可能存在數(shù)據(jù)的男韧。因此,clear 方法是弱一致的默垄。
為何多 個 線 程 并 發(fā) 修 改 ConcurrentHashMap 時 不 會 ConcurrentModificationException
在遍歷過程中此虑,如果已經遍歷的數(shù)組上的內容變化了,迭代器不會拋ConcurrentModificationException 異常口锭。如果未遍歷的數(shù)組上的內容發(fā)生了變化朦前,則有可能反映到迭代過程中介杆。這就是 ConcurrentHashMap 迭代器弱一致的表現(xiàn)。
在這種迭代方式中韭寸,當 iterator 被創(chuàng)建后春哨,集合再發(fā)生改變就不再是拋出ConcurrentModificationException,取而代之的是在改變時 new 新的數(shù)據(jù)從而不影響原有的數(shù)據(jù)恩伺,iterator 完成后再將頭指針替換為新的數(shù)據(jù)赴背,這樣iterator 線程可以使用原來老的數(shù)據(jù),而寫線程也可以并發(fā)的完成改變晶渠,更重要的凰荚,這保證了多個線程并發(fā)執(zhí)行的連續(xù)性和擴展性,是性能提升的關鍵褒脯。