Java中ConcurrentHashMap的实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java中ConcurrentHashMap的实现ConcurrentHashMap(简称CHM)是在Java 1.5作为Hashtable的替代选择新引⼊的,是concurrent包的重要成员。

在Java 1.5之前,如果想要实现⼀个可以在多线程和并发的程序中安全使⽤的Map,只能在HashTable和synchronized Map中选择,因为HashMap并不是线程安全的。

但再引⼊了CHM之后,我们有了更好的选择。

CHM不但是线程安全的,⽽且⽐HashTable和synchronizedMap的性能要好。

相对于HashTable和synchronizedMap锁住了整个Map,CHM只锁住部分Map。

CHM允许并发的读操作,同时通过同步锁在写操作时保持数据完整性。

我们已经在Top 5 Java Concurrent Collections from JDK 5 and 6中学习了CHM的基础知识,在这篇博客中我将介绍以下⼏点:
1. CHM在Java中如何实现的
2. 什么情况下应该使⽤CHM
3. 在Java中使⽤CHM的例⼦
4. CHM的⼀些重要特性
Java中ConcurrentHashMap的实现
CHM引⼊了分割,并提供了HashTable⽀持的所有的功能。

在CHM中,⽀持多线程对Map做读操作,并且不需要任何的blocking。

这得益于CHM将Map分割成了不同的部分,在执⾏更新操作时只锁住⼀部分。

根据默认的并发级别(concurrency level),Map被分割成16个部分,并且由不同的锁控制。

这意味着,同时最多可以有16个写线程操作Map。

试想⼀下,由只能⼀个线程进⼊变成同时可由16个写线程同时进⼊(读线程⼏乎不受限制),性能的提升是显⽽易见的。

但由于⼀些更新操作,如put(),remove(),putAll(),clear()只锁住操作的部分,所以在检索操作不能保证返回的是最新的结果。

另⼀个重要点是在迭代遍历CHM时,keySet返回的iterator是弱⼀致和fail-safe的,可能不会返回某些最近的改变,并且在遍历过程中,如果已经遍历的数组上的内容变化了,不会抛出ConcurrentModificationExceptoin的异常。

CHM默认的并发级别是16,但可以在创建CHM时通过构造函数改变。

毫⽆疑问,并发级别代表着并发执⾏更新操作的数⽬,所以如果只有很少的线程会更新Map,那么建议设置⼀个低的并发级别。

另外,CHM还使⽤了ReentrantLock来对segments 加锁。

Java中ConcurrentHashMap putifAbsent⽅法的例⼦
很多时候我们希望在元素不存在时插⼊元素,我们⼀般会像下⾯那样写代码
synchronized(map){
if (map.get(key) == null){
return map.put(key, value);
} else{
return map.get(key);
}
}
上⾯这段代码在HashMap和HashTable中是好⽤的,但在CHM中是有出错的风险的。

这是因为CHM在put操作时并没有对整个Map加锁,所以⼀个线程正在put(k,v)的时候,另⼀个线程调⽤get(k)会得到null,这就会造成⼀个线程put的值会被另⼀个线程put的值所覆盖。

当然,你可以将代码封装到synchronized代码块中,这样虽然线程安全了,但会使你的代码变成了单线程。

CHM提供的putIfAbsent(key,value)⽅法原⼦性的实现了同样的功能,同时避免了上⾯的线程竞争的风险。

什么时候使⽤ConcurrentHashMap
CHM适⽤于读者数量超过写者时,当写者数量⼤于等于读者时,CHM的性能是低于Hashtable和synchronized Map的。

这是因为当锁住了整个Map时,读操作要等待对同⼀部分执⾏写操作的线程结束。

CHM适⽤于做cache,在程序启动时初始化,之后可以被多个请求线程访问。

正如Javadoc说明的那样,CHM是HashTable⼀个很好的替代,但要记住,CHM的⽐HashTable的同步性稍弱。

总结
现在我们知道了什么是ConcurrentHashMap和什么时候该⽤ConcurrentHashMap,下⾯我们来复习⼀下CHM的⼀些关键点。

1. CHM允许并发的读和线程安全的更新操作
2. 在执⾏写操作时,CHM只锁住部分的Map
3. 并发的更新是通过内部根据并发级别将Map分割成⼩部分实现的
4. ⾼的并发级别会造成时间和空间的浪费,低的并发级别在写线程多时会引起线程间的竞争
5. CHM的所有操作都是线程安全
6. CHM返回的迭代器是弱⼀致性,fail-safe并且不会抛出ConcurrentModificationException异常
7. CHM不允许null的键值
8. 可以使⽤CHM代替HashTable,但要记住CHM不会锁住整个Map
以上就是Java中CHM的实现和使⽤场景,希望能帮助到⼤家!谢谢⼤家对本站的⽀持!。

相关文档
最新文档