SynchronizedMap
Collections.synchronizedMap,直接给集合中所有方法上锁。低效。值得一提的是,这种同步的方式是在类中增加一个信号量变量(默认为this),重写每个方法,都加上一句用synchronized包围的同步块。
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用来为索引的第一个节点加锁,这样相当于为整个链表或红黑树加锁。