ConcurrentHashMap
JDK1.5之后出现,因为HashTable虽然是线程安全的但是它是在方法前面加上的Sycronized锁 导致执行效率低下 许多线程同时访问的时候会出现阻塞或者轮询状态。而HashMap则是线程不安全的,下面就来讨论一下ConcurrenHashMap是如何实现线程安全的。
ConcurrentHashMap之所以较HashTable提高了性能最根本的原因就是,它不是对Hash表的整体进行加锁,而是采用分段锁的方式,它将整个Hash表分成多个Segment,一个ConcurrentHashMap中包含一个Segment数组,Segment是ReentrantLock(可重入锁),而每个Segment和Hash表类似,是数组链表结构的,意味着每个Segment维护着HashEntry数组 就想一个小的Hash表一样,而每个想要访问该段的线程都要获取该段的锁而不影响其他的Segment的操作。
CurrentHashMap的初始化
因为为了通过按位与的操作,所以Segment数组的长度会被保证初始化为2的整数倍,这样方便Hash,默认ConcurrencyLevel是16 sshift等于ssize从1向左移动的次数 segementMask是散列运算的掩码 等于32-sshift
注意初始化的时候 initialCapacity是ConcurrentHashMap的初始容量 loadfactor是Segment的装载因子。
Segment的初始化操作
initialCapacity默认16 loadFactory默认0.75
i
f(initialCapacity>MAXIMUM_CAPACITY)
initialCapacity=MAXIMUM_CAPACITY;
int c=initialCapacity/ssize;
if(c*ssize<initialCapacity) c++;
int cap=1;
//cap就是一个Segment中的HashEntry数组长度
if(cap<c)
cap<<=1;
for(int i=0;i<this.segments.length;++i)
this.segments[i]=new Segment<K,V>(cap,loadFactory);
定位Segment:
在进行Segment的定位之前 ConcurrentHashMap会对对象的Hash值进行一次再散列 再散列通过将Hash值的多次移位操作将原本的Hash值均匀分布,在进行Segment定位时候采用的是这样的算法:
final Segment