Java-API简析_java.util.concurrent.ConcurrentHashMap<K,V>类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/132527523
出自【进步*于辰的博客】

因为我发现目前,我对Java-API的学习意识比较薄弱,需要慢慢习惯使用Java-API,乃至剖析源码来提升自己的源码阅读能力和编码素质。
大家如果需要Java-API文档,我上传了【https://download.csdn.net/download/m0_69908381/87691693】。

文章目录

  • 1、概述

1、概述

继承关系:

  • java.lang.Object
    • java.util.AbstractMap
      • java.util.concurrent.ConcurrentHashMap

参数类型
K - 此映射维护的键的类型
V - 映射值的类型

实现的所有接口
Serializable , ConcurrentMap , Map


public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap, Serializable

一个哈希表,支持检索的完全并发和更新的高预期并发性。 此类遵循与 Hashtable 相同的功能规范,并包括与 Hashtable 每个方法对应的方法版本。 但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。 此类与 Hashtable 完全可互操作, Hashtable 程序依赖于其线程安全性,但不依赖于其同步细节。

检索操作(包括get() )一般不会阻塞,因此可能与更新操作重叠(包括put和remove() )。 检索反映了最近完成的更新操作的结果。 (更正式地说,给定密钥的更新操作承担与报告更新值的该密钥的任何(非空)检索之前发生的关系。)对于诸如putAll()clear()类的聚合操作,并发检索可能反映插入或删除只有一些条目。 类似地,Iterators,Spliterators和 Enumerations 在迭代器/枚举的创建时或之后的某个时刻返回反映哈希表状态的元素。 他们不扔ConcurrentModificationException 。 但是,迭代器设计为一次只能由一个线程使用。 请记住,骨料状态方法的结果,包括size()isEmpty()containsValue()通常是有用的,只有当一个地图没有发生在其他线程并发更新。 否则,这些方法的结果反映了可能足以用于监视或估计目的的瞬态,但不适用于程序控制

当存在太多冲突时(即,具有不同哈希码的密钥但落入与表大小模数相同的槽中的密钥),该表被动态扩展,具有每个映射大致保持两个箱的预期平均效果(对应于0.75负载)调整大小的因子阈值)。 随着映射的添加和删除,这个平均值可能会有很大的差异,但总的来说,这维持了哈希表的普遍接受的时间/空间权衡。 但是,调整此大小或任何其他类型的散列表可能是一个相对较慢的操作。 如果可能,最好将大小估计值作为可选的initialCapacity()构造函数参数提供。 另一个可选的loadFactor()构造函数参数提供了另一种通过指定在计算给定数量的元素时要分配的空间量时使用的表密度来自定义初始表容量的方法。 此外,为了与此类的先前版本兼容,构造函数可以选择将预期的concurrencyLevel指定为内部大小调整的附加提示。 请注意,使用具有完全相同的hashCode()许多键是降低任何哈希表性能的可靠方法。 为了改善影响,当键为Comparable时 ,此类可以使用键之间的比较顺序来帮助打破关系。

可以创建一个 ConcurrentHashMap 的 Set 投影(使用newKeySet()newKeySet(int) ),或查看(仅使用感兴趣的键时使用keySet(Object) ,并且映射的值(可能是暂时的)未使用或者全部采用相同的映射值。

通过使用LongAdder值并通过computeIfAbsent()初始化,ConcurrentHashMap 可用作可伸缩频率映射(直方图或多集的形式)。 例如,要将计数添加到ConcurrentHashMap freqs ,可以使用freqs.computeIfAbsent(key, k -> new LongAdder()).increment();

此类及其视图和迭代器实现了 Map 和 Iterator 接口的所有可选方法。

像 Hashtable 但不像 HashMap ,这个类不允许 null用作键或值。

ConcurrentHashMaps 支持一组顺序并行批量操作,与大多数Stream()方法不同,它们被设计为安全且通常合理地应用,即使是由其他线程同时更新的映射; 例如,在共享注册表中计算值的快照摘要时。 有三种操作,每种操作有四种形式,接受带有键,值,条目和(键,值)对的函数作为参数和/或返回值。 因为 ConcurrentHashMap 的元素没有以任何特定的方式排序,并且可以在不同的并行执行中以不同的顺序处理,所提供的函数的正确性不应该依赖于任何排序,或者可能依赖于任何其他可能瞬时变化的对象或值。计算正在进行中; 除了forEach动作外,理想情况下应该是无副作用的。 Map.Entry对象上的批量操作不支持方法setValue()

  • forEach:对每个元素执行给定的操作。 变量形式在执行操作之前对每个元素应用给定的变换。
  • search:返回在每个元素上应用给定函数的第一个可用的非null结果; 在找到结果时跳过进一步搜索。
  • reduce:累积每个元素。 提供的缩减功能不能依赖于排序(更正式地说,它应该是关联的和可交换的)。 有五种变体:
    • 简单减少。 (对于(key,value)函数参数,没有这种方法的形式,因为没有相应的返回类型。)
    • 映射缩减,累积应用于每个元素的给定函数的结果。
    • 使用给定的基值减少标量的双精度,长数和整数。

这些批量操作接受parallelismThreshold参数。 如果估计当前地图大小小于给定阈值,则方法顺序进行。 使用值Long.MAX_VALUE抑制所有并行性。 使用值1通过划分为足够的子任务来充分利用用于所有并行计算的ForkJoinPool.commonPool() ,从而实现最大并行度。 通常,您最初会选择其中一个极值,然后测量使用中间值的性能,这些值会影响开销与吞吐量之间的差异。

批量操作的并发属性遵循 ConcurrentHashMap 的并发属性:从get(key)返回的任何非空结果和相关的访问方法都与相关的插入或更新具有先发生关系。 任何批量操作的结果都反映了这些每元素关系的组成(但不一定是整个地图的原子,除非它以某种方式被称为静止)。 相反,因为映射中的键和值永远不为null,所以null可以作为当前缺少任何结果的可靠原子指示符。 为了维护此属性,null用作所有非标量缩减操作的隐式基础。 对于double,long 和 int 版本,基础应该是一个,当与任何其他值组合时,返回其他值(更正式地说,它应该是减少的标识元素)。 最常见的减少具有这些特性; 例如,用基数MAX_VALUE计算基数为0或最小值的和。

作为参数提供的搜索和转换函数应该类似地返回null以指示缺少任何结果(在这种情况下不使用它)。 在映射缩减的情况下,这也使变换能够用作过滤器,如果不应该组合元素,则返回null(或者,如果是原始特化,则返回标识基础)。 您可以在搜索或减少操作中使用它们之前,通过在“null表示现在没有任何内容”规则下自己编写复合变换和过滤来创建复合变换和过滤。

接受和/或返回Entry参数的方法维护键值关联。 例如,当找到具有最大价值的密钥时,它们可能是有用的。 请注意,可以使用new AbstractMap.SimpleEntry(k,v)提供“plain” Entry 参数。

批量操作可能会突然完成,抛出在应用函数中遇到的异常。 在处理此类异常时请记住,其他并发执行的函数也可能抛出异常,或者如果没有发生第一个异常,则会这样做。

与顺序形式相比,并行加速是常见的,但不能保证。 如果并行计算的基础工作比计算本身更昂贵,则涉及小地图上的简短函数的并行操作可能比顺序形式执行得更慢。 类似地,如果所有处理器忙于执行不相关的任务,则并行化可能不会导致太多实际的并行性。

所有任务方法的所有参数都必须为非null

此类是Java Collections Framework的成员。

从以下版本开始:
1.5
另请参见:
Serialized Form


本文持续更新中。。。

你可能感兴趣的:(Java-API,Java-API简析,ConcurrentHashM)