ConcurrentHashMap

 

===============================================================================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的異常

不少時候咱們但願在元素不存在時插入元素,咱們通常會像下面那樣寫代碼安全

  • 上面這段代碼在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中
相關文章
相關標籤/搜索