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

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

1、概述

继承关系:

  • java.lang.Object
    • java.util.AbstractMap<K, V>
      • java.util.concurrent.ConcurrentHashMap<K,V>

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

实现的所有接口
Serializable , ConcurrentMap<K, V>,Map<K, V>


public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>, 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<String,LongAdder> 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

2、构造方法摘要

2.1 null

创建一个带有默认初始容量、加载因子和 concurrencyLevel 的新的空映射。

2.2 int initialCapacity

创建一个带有指定初始容量、默认加载因子和 concurrencyLevel 的新的空映射。

2.3 int initialCapacity, float loadFactor, int concurrencyLevel

创建一个带有指定初始容量、加载因子和并发级别的新的空映射。

2.4 Map<? extends K, ? extends V> t

构造一个与给定映射具有相同映射关系的新映射。

3、方法摘要

3.1 void clear()

从该映射中移除所有映射关系。

3.2 boolean contains(Object value)

一种遗留方法,测试此表中是否有一些与指定值存在映射关系的键。

3.3 boolean containsKey(Object key)

测试指定对象是否为此表中的键。

3.4 boolean containsValue(Object value)

如果此映射将一个或多个键映射到指定值,则返回 true。

3.5 Enumeration<V> elements()

返回此表中值的枚举。

3.6 Set<Map.Entry<K,V>> entrySet()

返回此映射所包含的映射关系的 collection 视图。

3.7 V get(Object key)

返回此表中指定键所映射到的值。

3.8 boolean isEmpty()

如果此映射不包含任何键-值映射关系,则返回 true。

3.9 Enumeration<K> keys()

返回此表中键的枚举。

3.10 Set<K> keySet()

返回此映射中包含的键的 set 视图。

3.11 V put(K key, V value)

将指定 key 映射到此表中的指定 value。

3.12 void putAll(Map<? extends K, ? extends V> t)

将指定映射中所有映射关系复制到此映射中。

3.13 V putIfAbsent(K key, V value)

如果指定键已经不再与某个值相关联,则将它与给定值关联。

3.14 V remove(Object key)

从此表中移除键(及其相应的值)。

3.15 boolean remove(Object key, Object value)

只有目前将键的条目映射到给定值时,才移除该键的条目。

3.16 V replace(K key, V value)

只有目前将键的条目映射到某一值时,才替换该键的条目。

3.17 boolean replace(K key, V oldValue, V newValue)

只有目前将键的条目映射到给定值时,才替换该键的条目。

3.18 int size()

返回此映射中键-值映射关系的数量。

3.19 Collection values()

返回此映射中包含的值的 collection 视图。

最后

本篇文章对此类的源码解析仅是“浅析”,如果大家想要深入掌握,可查阅博文《Map 综述(三):彻头彻尾理解 ConcurrentHashMap》(转发)。

如果大家需要Java-API文档,我上传了《Java-API文档-包含5/8/11三个版本》。


本文暂缓更新。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进步·于辰

谢谢打赏!!很高兴可以帮到你!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值