ConcurrentHashMap篇一

ConcurrentHashMap,1个10面9问的类,首先看下JDK1.8下这个类的类注释:
  1. 类注释:(没必要看,翻译一遍跟没翻译没啥区别,从中几乎得不到任何有用的知识点)

       支持全并发检索和高预期的并发更新的哈希表, 遵循和HashTable相同的功能规范, 并且他包含的方法版本号也对应于HashTable中每个方法版本号, 尽管所有的操作都是线程安全的, 检索操作不需要加锁,而且也不支持以锁定整个表的方式来阻止所有访问. 它在依赖其线程安全性而非依赖其同步细节的程序中可以和HashTable完全互(换)操作.

       检索操作(包括get)通常不阻塞,所以可能会与更新操作(包括put和remove)相叠加,所有的检索显示的结果都是最近完成的更新操作开始时所持有的值.(正式点来讲,对于一个key的更新操作与返回这个key更新值的任何(非空)检索操作之间承载着一个happens-before的关系),对于像putAll和clear这种聚合操作来说,并发的检索可能仅仅发生在某些元素的插入或者删除上,类似地,Iterators, Spliterators和Enumerations返回的元素反映了哈希表在iterator或enumeration创建时或创建后的某个点的状态,而且,这些操作也不会抛出ConcurrentModificationException, 然而, 迭代器被设计为一次仅被一个线程使用,请记住,聚合状态方法(包括size、isEmpty和containsValue)的结果通常是有用的,仅当映射其他线程没有经历并发更新时,但是,这些方法的结果反映的瞬间状态可能勉强能满足监测或评估的目的,但不能在程序控制中使用(就是前面的聚合状态方法的返回值)。

       当冲突太多时,表会动态扩展(冲突指的是:不同哈希值的key,其哈希值跟表的容量之间取模后使其落在相同的槽里),预期的平均效果是每个映射保持大约两个存储单元(对应于0.75的负载因子扩容阈值),随着映射的添加和删除,这个平均值可能会有很大的差异,但整体来说,这为哈希表保持了一个普遍接受的时间/空间权衡.然而,调整这个或任何其他类型的哈希表的大小可能是一个相对缓慢的操作.如果可能,最好提供一个大小估计值作为可选的initialCapacity构造函数参数,另一个可选参数loadFactor构造函数, 提供了一种更进一步的可以自定义哈希表初始表容量的方法, 它指定了计算给定数量的元素分配空间大小所需的表密度.此外,为了与该类的早期版本兼容,构造函数可以选择指定预期的并发级别,作为内部大小调整的额外提示.请注意,使用具有完全相同hashCode()方法的多个键肯定会降低任何哈希表的性能,为了改善影响,当键实现了Comparable接口时,该类可以使用键之间的比较顺序来帮助打破联系.

       ConcurrentHashMap的集合映射可以(使用newKeySet()或newKeySet(int))创建,当只关注键时也可以(使用keySet(Object))查看,并且键映射的值(可能暂时)没有使用,或者全部采用相同的映射值.

       通过使用LongAdder的值并且通过 computeIfAbsent初始化, 使得ConcurrentHashMap可以用作可伸缩频率图(直方图或多集的一种形式).例如你可以使用freqs.computeIfAbsent(k -> new LongAdder()).increment(),向一个ConcurrentHashMap<String,LongAdder> freqs对象中新增一个计数(进行一个累加操作).

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

       (在键值能否为空上)与Hashtable相同,但和HashMap不同的是ConcurrentHashMap键和值都不能为空

        与大多数Stream方法不同的是,ConcurrentHashMaps支持一组顺序和并行的批量操作,这些操作被设计为安全且通常合理地应用于其他线程同时更新maps;例如,在计算共享注册表中的值的快照摘要时.有三种操作,每种操作有四种形式,接受带有Keys,Values, Entries和(Key, Value)参数的函数.因为ConcurrentHashMap的元素没有以任何特定的方式排序,并且可以在不同的并行执行中以不同的顺序进行处理,所以提供的函数的正确性不应该取决于任何排序,或者在计算过程中可能暂时改变的任何其他对象或值;除了forEach操作外,理想情况下应无副作用。在Map.Entry对象中进行批量操作时不支持使用setValue方法

  • forEach:对每个元素都执行给定的操作.在执行操作前,每个元素以变量的形式应用于给定的转换
  • search:对每个元素上执行给定的函数返回第一个可能非空结果,找到结果时跳过进一步搜索
  • reduce:对每个元素进行累加,提供的归约函数不能依赖排序(正式点说,它应该是满足交换律和结合律)
  •           普通归约(这个方法没有任何的格式,只是简单(key, value)形式的函数式接口参数,也不需要返回值)
  •           映射归约就是对每个元素应用给定的函数得出累加结果(我的理解:这个就是Java8中的mapping操作,把元素或者元素里的某个熟悉在某个累加函数中处理,然后对处理结果进行类型转换,得到一个新的类型的返回值)
  •           使用给定的基值,将将其归约为标量double、long和int

        这些批量操作接受parallellismthreshold参数,如果当前map的大小评估小于给定的阈值,方法将顺序处理,最大并行量Long.MAX_VALUE,将ForkJoinPool.commonPool() 充分用于所有并行计算,并划分足够多的子任务使得并行效率100%,通常情况下,首先会选择某个极值,然后通过性能测试在开销和吞吐量之间权衡出一个中间值

       批量操作的并发属性遵循ConcurrentHashMap的并发属性:get(key)和相关的访问方法返回的任何非空结果都和相关的插入或者更新之间存在happens-before关系,任何批量操作的结果都反映了这些单个元素的组合关系(但就整个map而言,不一定是原子的,除非知道它是静态的),相反地,由于map中的key和value从不为null,因此null可以作为当前缺少任何结果的可靠原子指示器,为了维护这个属性,null作为所有非标量归约操作的隐式基础, 对于double,long和int版本,基础应该是一个,当与任何其他值组合时,返回该其他值(更正式地说,它应该是归约的标识元素),大多数普通的归约拥有这些属性,例如,计算基于0的求和或者1个基于MAX_VALUE的最小值.

       作为参数提供的搜索和转换函数同样应该返回null,以指示缺少任何结果(在这种情况下不要使用),在映射归约的情况下,它也能够讲转换操作作为过滤操作,返回null,(或者,在基元专门化情况下,返回标识)如果元素不被组合.在进行搜索和归约操作使用复合的转换和过滤前,可以基于"null代表没有任何值"的规则下对他们进行组合.

       方法接受and/or返回Entry参数,保持key-value关联,例如,在找在找到最大值的Key时,这样可能很有用,注意,普通的Entry参数能够用于创建new AbstractMap.SimpleEntry(k,v).

       批量操作可能突然终止,抛出异常发生于应用中提供的函数中,请记住,在处理此类异常时,其他并发执行的函数也可能抛出异常,或者在第一个异常未发生时也会抛出异常.

       与顺序形式相比,并行形式的加速是常见的,但不能保证.如果计算并行化的底层工作比计算本身更昂贵,则涉及小maps上的简短函数的并行操作可能比顺序形式执行得慢,类似的,如果所有的CPU都在忙于执行无关的任务,并行化可能并不能带来太多实际的并行性.

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

此类是Java集合框架的成员。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值