put操作
[Java] 纯文本查看 复制代码 public V put(K paramK, V paramV)
{
if (paramV == null)
throw new NullPointerException();
int i = hash(paramK.hashCode());
return segmentFor(i).put(paramK, i, paramV, false);
}
与HashMap不同的是,如果key为null,直接抛出NullPointer异常,之后,同样先计算hashCode的值,再计算hash值,不过此处hash函数和HashMap中的不一样:
[Java] 纯文本查看 复制代码 private static int hash(int paramInt)
{
paramInt += (paramInt << 15 ^ 0xFFFFCD7D);
paramInt ^= paramInt >>> 10;
paramInt += (paramInt << 3);
paramInt ^= paramInt >>> 6;
paramInt += (paramInt << 2) + (paramInt << 14);
return (paramInt ^ paramInt >>> 16);
}
[Java] 纯文本查看 复制代码 final Segment<K, V> segmentFor(int paramInt)
{
return this.segments[(paramInt >>> this.segmentShift & this.segmentMask)];
}
根据上述代码找到Segment对象后,调用put来操作:
[Java] 纯文本查看 复制代码 V put(K paramK, int paramInt, V paramV, boolean paramBoolean)
{
lock();
try {
Object localObject1;
Object localObject2;
int i = this.count;
if (i++ > this.threshold)
rehash();
ConcurrentHashMap.HashEntry[] arrayOfHashEntry = this.table;
int j = paramInt & arrayOfHashEntry.length - 1;
ConcurrentHashMap.HashEntry localHashEntry1 = arrayOfHashEntry[j];
ConcurrentHashMap.HashEntry localHashEntry2 = localHashEntry1;
while ((localHashEntry2 != null) && (((localHashEntry2.hash != paramInt) || (!(paramK.equals(localHashEntry2.key)))))) {
localHashEntry2 = localHashEntry2.next;
}
if (localHashEntry2 != null) {
localObject1 = localHashEntry2.value;
if (!(paramBoolean))
localHashEntry2.value = paramV;
}
else {
localObject1 = null;
this.modCount += 1;
arrayOfHashEntry[j] = new ConcurrentHashMap.HashEntry(paramK, paramInt, localHashEntry1, paramV);
this.count = i;
}
return localObject1;
} finally {
unlock();
}
}
先调用lock(),lock是ReentrantLock类的一个方法,用当前存储的个数+1来和threshold比较,如果大于threshold,则进行rehash,将当前的容量扩大2倍,重新进行hash。之后对hash的值和数组大小-1进行按位于操作后,得到当前的key需要放入的位置,从这儿开始,和HashMap一样。
从上述的分析看出,ConcurrentHashMap基于concurrentLevel划分出了多个Segment来对key-value进行存储,从而避免每次锁定整个数组,在默认的情况下,允许16个线程并发无阻塞的操作集合对象,尽可能地减少并发时的阻塞现象。在多线程的环境中,相对于HashTable,ConcurrentHashMap会带来很大的性能提升!
|