HashMap的线程安全解决方案

SynchronizedMap

Collections.synchronizedMap,直接给集合中所有方法上锁。低效。

Hashtable

直接给集合中所有方法上锁。低效。

1.7 ConcurrentHashMap

concurrentHashMap是弱一致性,hashTable是强一致性。

分段锁Segment

ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock。

访问全局先乐观后悲观

相比于对整个Map加锁的设计,分段锁大大的提高了高并发环境下的处理能力。但同时,由于不是对整个Map加锁,导致一些需要扫描整个Map的方法(如size(), containsValue())需要使用先乐观后悲观的实现方法。

volatile保持可见性

ConcurrentHashMap中的HashEntry相对于HashMap中的Entry有一定的差异性:HashEntry中的value以及next都被volatile修饰,这样在多线程读写过程中能够保持它们的可见性。

设置并发度

ConcurrentHashMap默认的并发度为16,但用户也可以在构造函数中设置并发度。当用户设置并发度时,ConcurrentHashMap会使用大于等于该值的最小2幂指数作为实际并发度(假如用户设置并发度为17,实际并发度则为32)。

延迟化加载第二个开始的segment

和JDK6不同,JDK7中除了第一个Segment之外,剩余的Segments采用的是延迟初始化的机制:每次put之前都需要检查key对应的Segment是否为null,如果是则调用ensureSegment()以确保对应的Segment被创建。

1.8 ConcurrentHashMap

sizeCtl

首先来看几个重要的属性,与HashMap相同的就不再介绍了,这里重点解释一下sizeCtl这个属性。可以说它是ConcurrentHashMap中出镜率很高的一个属性,因为它是一个控制标识符,在不同的地方有不同用途,而且它的取值不同,也代表不同的含义。

  • 负数代表正在进行初始化或扩容操作
  • -1代表正在初始化
  • -N 表示有N-1个线程正在进行扩容操作
  • 正数或0代表hash表还没有被初始化,这个数值表示初始化或下一次进行扩容的大小,这一点类似于扩容阈值的概念。它的值始终是当前ConcurrentHashMap容量的0.75倍,这与loadfactor是对应的。

CAS

在判断是否hash后找到的节点为null时使用CAS方法判断。

同步节点

synchronize用来为索引的第一个节点加锁,这样相当于为整个链表或红黑树加锁。

猜你喜欢

转载自blog.csdn.net/quinnnorris/article/details/81005071
今日推荐