// All entries following removed node can stay
// in list, but all preceding ones need to be
// cloned.
++modCount;
HashEntry
for (HashEntry
newFirst = new HashEntry
newFirst, p.value);//2.注意看这里,就是逐个复制。
tab[index] = newFirst;
count = c; // write-volatile 3.这里依然是JSR 166 保证线程间可见性。
}
}
return oldValue;
} finally {
unlock();
}
}
在删除之前依然是:
Java代码
public V remove(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).remove(key, hash, null);
}
其中get方法和remove方法都调用了一个segmentFor()方法,其实并发HashMap的所有操作都和这个方法有关。到底是如何实现的呢?
Java代码
/**
* Returns the segment that should be used for key with given hash
* @param hash the hash code for the key
* @return the segment
*/
final Segment
return segments[(hash >>> segmentShift) & segmentMask];
}
需要特别注意一下segmentShift和segmentMask,假设构造函数确定了Segment的数量是2的n次方,那么segmentShift就等于32减去n,而segmentMask就等于2的n次方减一。一般最常见的值是Segment数量2^4 = 16,segmentShift=28,segmentMask=15,经过segmentFor()运算就能快速的定位到具体的Segment上面。
Java代码
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
public V putIfAbsent(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, true);
}
put方法和putIfAbsent方法都调用了Segment的put(etc...)方法,仅仅只是最后一个参数不同:
Java代码
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry
int index = hash & (tab.length - 1);
HashEntry
HashEntry
while (e != null && (e.hash != hash || !key.equals(e.key)))
e = e.next;
V oldValue;
if (e != null) {
oldValue = e.value;
if (!onlyIfAbsent)//不同之处,在这里体现。
e.value = value;
}
else {
oldValue = null;
++modCount;
tab[index] = new HashEntry
count = c; // write-volatile 最后写volatile变量,保证可见性
}
return oldValue;
} finally {
unlock();
}
}
并发HashMap的put和putIfAbsent的区别就是一个是直接放入并替换,另一个是有就不替换。其它方法诸如clear(),replace()等,都是在细粒度的锁下完成的。这里不做更细的讨论,详见并发HashMap