===============================================================================html
ConcurrentHashMap(簡稱CHM
)是在Java 1.5做爲Hashtable
的替代選擇新引入的,是concurrent包的重要成員java
在Java 1.5以前,若是想要實現一個能夠在多線程和併發的程序中安全使用的Map,只能在HashTable和synchronized Map中選擇數組
- 由於HashMap並非線程安全的
- ConcurrentHashMap不可是線程安全的,並且比HashTable和synchronizedMap的性能要好
- 根據默認的併發級別(
concurrency level
),Map被分割成16個部分,而且由不一樣的鎖控制
- 這意味着,同時最多能夠有16個寫線程操做Map
- 試想一下,由只能一個線程進入變成同時可由16個寫線程同時進入(讀線程幾乎不受限制),性能的提高是顯而易見的
- 在迭代遍歷CHM時,keySet返回的iterator是弱一致和fail-safe的,可能不會返回某些最近的改變
- 而且在遍歷過程當中,若是已經遍歷的數組上的內容變化了,不會拋出ConcurrentModificationExceptoin的異常
不少時候咱們但願在元素不存在時插入元素,咱們通常會像下面那樣寫代碼安全
![](http://static.javashuo.com/static/loading.gif)
- 上面這段代碼在HashMap和HashTable中是好用的,但在CHM中是有出錯的風險的
- CHM的比HashTable的同步性稍弱
- 這是由於CHM在put操做時並無對整個Map加鎖,因此一個線程正在put(k,v)的時候
- 另外一個線程調用get(k)會獲得null,這就會形成一個線程put的值會被另外一個線程put的值所覆蓋
- 這就是對segment 加鎖的緣由
- 上面的map 僅僅是鎖對象,不表明別的線程不能使用map ,僅僅表明別的線程不能進入該代碼塊
- CHM提供的putIfAbsent(key,value)方法原子性的實現了一樣的功能,同時避免了上面的線程競爭的風險
總結
- CHM容許併發的讀和線程安全的更新操做
- 在執行寫操做時,CHM只鎖住部分的Map
- 併發的更新是經過內部根據併發級別將Map分割成小部分實現的
- 高的併發級別會形成時間和空間的浪費,低的併發級別在寫線程多時會引發線程間的競爭
- CHM的全部操做都是線程安全
- CHM返回的迭代器是弱一致性,fail-safe而且不會拋出ConcurrentModificationException異常
- 由於每次更新內容時,僅僅是鎖一個segment,不是整個map鎖定
- CHM不容許null的鍵值
- 可使用CHM代替HashTable,但要記住CHM不會鎖住整個Map
從ConcurrentHashMap代碼中能夠看出,它引入了一個「分段鎖」的概念多線程
- 具體能夠理解爲把一個大的Map拆分紅N個小的HashTable,根據key.hashCode()來決定把key放到哪一個HashTable中
- 就是把Map分紅了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪一個Segment中