相对于HashMap,ConcurrentHashMap提供了内部实现的并发支持。使得开发者在多线程应用中访问ConcurrentHashMap时,不必使用synchronized同步代码块。
- //Initialize ConcurrentHashMap instance
- ConcurrentHashMap<String, Integer> m = new ConcurrentHashMap<String, Integer>();
- //Print all values stored in ConcurrentHashMap instance
- for each (Entry<String, Integer> e : m.entrySet())
- {
- system.out.println(e.getKey()+"="+e.getValue());
- }
上述代码是在多线程应用中创建并使用ConcurrentHashMap的“理论上可行”的示例。这里的“理论上可行”是指,上述代码虽然能够保证 线程安全,但是还是会降低程序性能。但ConcurentHashMap是为了保证线程安全(优于HashMap)的同时改善性能(优于 Hashtable),不是吗?
哪里有问题呢?
为了搞清楚,我们需要理解ConcurrentHashMap类的内部工作原理。我们最好是从构造函数参数开始。 ConcurrentHashMap完整的构造函数需要三个参数:initialCapacity(初始容量),loadFactory(加载因 子),concurrencyLevel(并发级别)。
- initialCapacity:初始容量。ConcurrentHashMap的实现基于加载因子,进行内部分配以容纳这么多元素。
- loadFactor:加载因子(表密度),用于建立初始表的大小
- concurrencyLevel:并发级别,表示预计的同步更新线程的数量。
前两个参数比较容易理解;并发级别表示分片(shard)的数量,用于在ConcurrentHashMap内部分为相应的分区,同时相同数量的线程被创建,用于在分片级别保证线程安全。
concurrencyLevel的默认值为16。这意味着我们只要使用默认构造函数创建一个ConcurrentHashMap时,就会创建16 个分片——在我们向map中加入任何键值对之前。它同时意味着各种内部类的实例被创建,如ConcurrentHashMap$Segment, ConcurrentHashMap$HashEntry[] 和ReentrantLock$NofairSync。
多数情况下,一个分片已经足够处理通常键值对数量的多线程,同时性能也会被优化。创建多个分片只会使得内部实现更加复杂,同时引入许多不必要的对象,这一切都不利于改善性能。
每个使用默认构造函数创建的concurrent hashmap,创建冗余对象的比例约为1到50。例如,没创建100个ConcurrentHashMap实例,将会创建5000个冗余对象。
基于以上讨论,一个建议是更明智地使用构造函数参数,以减少冗余对象,同时提高性能。
ConcurrentHashMap更好的初始化方式:
- ConcurrentHashMap<String, Integer> instance = new ConcurrentHashMap<String, Integer>(16, 0.9f, 1);
初始容量16能够在扩容发生之前容纳足够多的元素。加载因子0.9保证了ConcurrentHashMap内部的致密堆积,以优化内存使用。并发级别设置为1,使得只有一个分片被创建和维护。
请注意,如果你的高并发应用程序更新ConcurrentHashMap的频率很高,你应当考虑增大concurrencyLevel,具体数值应该进行严谨的计算、测试以评估。
译者注:JDK1.8起通过默认构造函数创建的ConcurrentHashMap,其concurrencyLevel已被设置为1。
- /**
- * Creates a new, empty map with an initial table size based on
- * the given number of elements ({@code initialCapacity}) and
- * initial table density ({@code loadFactor}).
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements,
- * given the specified load factor.
- * @param loadFactor the load factor (table density) for
- * establishing the initial table size
- * @throws IllegalArgumentException if the initial capacity of
- * elements is negative or the load factor is nonpositive
- *
- * @since 1.6
- */
- public ConcurrentHashMap(int initialCapacity, float loadFactor) {
- this(initialCapacity, loadFactor, 1);
- }
原文写于JDK 1.8发布之前,可以作为JDK 1.8如此优化的解释。
原文链接:Java ConcurrentHashMap Best Practices
又及:
ConcurrentHashMap源码值得再读。相关文章:
http://cwind.iteye.com/blog/2280910
相关推荐
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
java源码剖析-ConcurrentHashMap
java本地缓存ConcurrentHashMap
Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;Java——并发容器之ConcurrentHashMap;...Java——并发容器之ConcurrentHashMapJava——并发容器之ConcurrentHashMap
Java并发编程之ConcurrentHashMap Java并发编程之ConcurrentHashMap.pdf
Java 7_ConcurrentHashMap.jpg
ConcurrentHashMap是一个线程安全的HashTable,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法。ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的...
主要介绍了java ConcurrentHashMap锁分段技术详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
java7-8中的 HashMap和ConcurrentHashMap全解析 如果你想了解底层的逻辑就来看看吧
主要介绍了Java中遍历ConcurrentHashMap的四种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
java7-8中的 HashMap和ConcurrentHashMap全解析
本文主要介绍Java 中ConcurrentHashMap的实现,这里整理了详细的资料,及简单实例代码,有兴趣的小伙伴可以参考下
Java concurrency集合之ConcurrentHashMap_动力节点Java学院整理,动力节点口口相传的Java黄埔军校
ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的...
ConcurrentHashMap使用了分段锁(Segment)来实现并发的读写操作,每个Segment都相当于一个小的HashMap,将整个哈希表分成多个部分。这样可以同时进行多个线程的并发读写操作,不会阻塞其他线程的访问。 需要注意的...
java EHCache使用,Hibernate缓存 收集整理
主要为大家详细分析了Java并发系列之ConcurrentHashMap源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
ConcurrentHashMap源码剖析
Java-concurrent-collections-concurrenthashmap-blockingqueue.pdf
主要介绍了java基于ConcurrentHashMap设计细粒度实现代码,通过ConcurrentHashMap实现细粒度,具有一定参考价值,需要的朋友可以了解。