`
cywhoyi
  • 浏览: 415027 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

翻译一篇关于ConcurrentHashMap的扼要

 
阅读更多

线程安全问题在我们应用中无处不在。线程非安全的HashMap的put()、get()操作会触发引起死循环的问题。有三种不同的同步map操作

1.HashTable

2.Collection.synchronizedMap(Map)

3.ConcurrentHashMap

ConcurrentHashMap实在JDK1.5以后引入,它是最为线程同步Map中优先级被推荐高于HashTable,不仅因为在高并发的情况下,ConcurrentHashMap支持线程同步,而且ConcurrentHashMap的性能比HashTable高,因为ConcurrentHashMap是锁住了部分Map,而HashTable和SynchronizedMap是锁住整个Map在有排序的操作中。

在ConcurrentHashMap的策略中,ConcurrentHashMap分解成不同的segments,每个segments 管理自己内部hash table。

锁发生在申请更新操作时候,在恢复的条件中,它同时也支持在高并发的条件下更新操作,获取最新的结果集。

我们假定有有4个线程访问一个容量为32的ConcurrentHashMap时候,我们可能会想要Table会分区成4segments,每个segments都管理容量为8的Hash table。

ConcurrentHashMap的数据结构可能会是这样。



 Segment

ConcurrentHashMap默认是有16segments,其中任意一个都关注、锁中map单一的bucket,意味着同一时间,16个线程能够修改Map(只有多个个取决于多少bucket),并发水平的增长依赖于concurrencylevel

 

public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel)

 最大是2的16次,用比较大的level,可能会浪费空间和时间,用的太小可能会引起线程的竞争。

 

Put Entry

ConcurrentHashMap不允许空值,它需要定位到segment的索引位置,以便于拿到准确的bucket

 

Put If Absent

ConcurrentMap offers new method putIfAbsent() which is similar to put except that the value will not be overridden if key already exists. This is equivalent to

 

except that the action is performed atomically.

containsKey is not synchronized so the above code may cause unexpected behavior. Lets look into the below scenario:

  1. Thread A is trying to remove a key, calls remove(key), acquires lock.
  2. Thread B tries to execute above code, calls containsKey(key). The key exists as Thread A has not yet released the lock so the old value is returned.
  3. Thread A removes the key and releases the lock.

The above scenario proves that the code is not atomic as it returned a key which it thinks exists but actually doesn’t.
Also, performance wise it is slow, containsKey has to locate the segment and traverse through the table to find the key. Method put needs to do the same traversing to locate the bucket and put the value. The new method putIfAbsent is a bit faster as it avoids double traversing. It goes through the same internal flow as put, avoids overriding the old value if key already exists and simply returns the old value.

Summary

Now we know What is ConcurrentHashMap in Java and when to use ConcurrentHashMap, it’s time to know and revise some important points about Concurrent HashMap in Java.
 
1. ConcurrentHashMap allows concurrent read and thread-safe update operation.
 
2. During update operation, ConcurrentHashMap only lock a portion of Map instead of whole Map.
 
3. Concurrent update is achieved by internally dividing Map into small portion which is defined by concurrency level.
 
4. Choose concurrency level carefully as a significant higher number can be waste of time and space and lower number may introduce thread contention in case writers over number concurrency level.
 
5. All operations of ConcurrentHashMap are thread-safe.
 
6. Since ConcurrentHashMap implementation doesn’t lock whole Map, there is chance of read overlapping with update operations like put() and remove(). In that case result returned by get() method will reflect most recently completed operation from there start.
 
7. Iterator returned by ConcurrentHashMap is weekly consistent, fail safe and never throw ConcurrentModificationException. In Java.
 
8. ConcurrentHashMap doesn’t allow null as key or value.
 
9. You can use ConcurrentHashMap in place of Hashtable but with caution as CHM doesn’t lock whole Map.
 
10. During putAll() and clear() operations, concurrent read may only reflect insertion or deletion of some entries.
 

 

  • 大小: 30.4 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics