相对于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源码值得再读。相关文章:
相关推荐
Java编码最佳实践是提高代码质量、可读性、性能和可维护性的关键。这份指南涵盖了多个方面的编程建议,旨在帮助开发者遵循良好的编程习惯,确保代码的高效运行。 1. **资源管理**:在处理文件、流或其他资源时,...
它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境下编写高效、安全的代码。 并发编程是现代软件开发中的关键技能,尤其是在Java这种支持多线程的语言中。Java并发API包括了线程、锁、同步、...
综上所述,“JAVA并发编程实践”这一主题涵盖了Java并发编程的基础概念、高级技术以及最佳实践等方面。掌握这些知识点对于开发高性能、高可用性的Java应用至关重要。希望以上内容能够帮助你更好地理解和应用Java并发...
这本书以实践为导向,详细介绍了Java平台上的并发编程技术和最佳实践。 Java并发编程的核心在于理解和使用Java的并发API,包括线程、锁、同步机制以及并发集合等。首先,书中会介绍Java中的线程基础知识,包括如何...
#### 五、Java并发编程最佳实践 在实际开发过程中,合理运用Java并发编程技术,不仅可以提高程序性能,还能简化复杂度。 ##### 5.1 减少锁的竞争 - 使用局部变量代替共享变量。 - 尽量减少锁的粒度,采用细粒度锁。...
通过《Java并发编程实践》这本书,读者可以深入了解Java并发编程的原理和最佳实践,提升编写高效、可靠的并发程序的能力。书中不仅讲解了理论知识,还提供了大量示例代码,有助于读者在实践中巩固所学。
8. **并发编程的最佳实践**:作者分享了一些实用的并发编程技巧和经验,帮助开发者写出更加稳定、高效的并发程序。 通过阅读《Java并发编程实践》,开发者不仅可以学习到Java并发编程的基础知识,还能了解到如何在...
《JVM高级特性与最佳实践(第2版)》是一本深入探讨Java虚拟机(JVM)技术的书籍,其源代码提供了丰富的实践案例和示例,帮助读者更直观地理解JVM的工作原理和优化技巧。以下是根据书名和描述所涉及的一些关键知识点...
Java提供了丰富的并发工具和API,如线程、锁、同步块、原子变量、并发容器等,而《Java并发编程实践》这本书正是对这些工具和最佳实践的详细解读。 1. **线程与进程**:在计算机系统中,线程是程序执行的基本单位,...
9. **并发编程的最佳实践** - 尽量减少共享状态。 - 使用不可变对象。 - 避免过度同步。 - 优先使用并发工具类而不是自建同步机制。 - 对于长时间运行的任务,考虑使用线程池。 以上内容涵盖了Java并发编程的...
7. **并发编程最佳实践**:总结了一系列的并发编程最佳实践,包括避免过度同步、使用并发工具而非手动锁、正确处理异常、避免线程阻塞等。 通过阅读《Java并发编程实践》这本书,读者不仅可以掌握Java并发编程的...
《Java并发编程实践》一书不仅阐述了理论知识,还提供了大量的实战案例和最佳实践。通过分析常见的并发问题和解决方案,读者可以学习到如何在实际项目中应用并发编程技巧,避免常见的陷阱和错误。 总之,《Java并发...
8. **并发编程最佳实践**:总结了在实际开发中应当遵循的一系列并发编程的最佳实践,以减少错误和提高程序的可靠性。 通过学习《JAVA并发编程实践》,开发者可以提升对Java并发编程的理解,掌握处理并发问题的关键...
第九章通常会总结并发编程的最佳实践,包括如何测试并发程序、使用并发工具进行性能调优,以及如何处理并发错误和异常。此外,可能还会探讨Java内存模型(JMM),它是理解线程间通信和可见性的理论基础。 总的来说...
书中还提到了一些最佳实践,如如何正确使用wait()和notify(),以及避免死锁和活锁的方法。 最后,本书还涵盖了Java并发编程的最新发展,如Fork/Join框架和Parallel Streams,这些是Java 7及以后版本引入的新特性,...