我已经读过,在Java中的并发hashmap中,同时插入是可能的,因为它被分成段并且为每个段采用单独的锁。 但是如果两个插入将在同一段上发生,那么这些同时发生就不会发生。 我的问题是在这种情况下会发生什么?第二次插入会等到第一次插入完成还是什么?
答案 0 :(得分:3)
一般来说,您不必过于关注ConcurrentHashMap
的实施方式。它只是符合ConcurrentMap
的合同,这确保了可以进行并发修改。
但要回答你的问题:是的,一次插入可能会等待另一次插入完成。在内部,它使用锁来确保一个线程在等待另一个线程释放锁。内部使用的类Segment
实际上继承自ReentrantLock
。以下是Segmenet.put()
的缩短版本:
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
HashEntry<K,V> node = tryLock() ? null : scanAndLockForPut(key, hash, value);
V oldValue;
try {
// modifications
} finally {
unlock();
}
return oldValue;
}
private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
// ...
int retries = -1; // negative while locating node
while (!tryLock()) {
if (retries < 0) {
// ...
}
else if (++retries > MAX_SCAN_RETRIES) {
lock();
break;
}
else if ((retries & 1) == 0 && (f = entryForHash(this, hash)) != first) {
e = first = f; // re-traverse if entry changed
retries = -1;
}
}
return node;
}
这可以给你一个想法。
答案 1 :(得分:3)
大多数并发数据结构的启发式方法是首先修改后备数据结构,其中前面的数据结构对外部方法可见。然后,当修改完成时,后备数据结构成为公共数据结构,公共数据结构被推到后面。除此之外,还有更多的方法,但这是典型的合同。
答案 2 :(得分:1)
如果在同一个网段上发生2次更新,他们会互相争执,其中一次必须等待。您可以通过选择concurrencyLevel值来优化它,该值考虑将同时更新hashmap的线程数。
中找到所有详细信息答案 3 :(得分:1)
ConcurrentHashMap包含Segment数组,而Segment又包含HashEntry数组。每个HashEntry都包含一个键,一个值和一个指向它的下一个相邻条目的指针。
但是它获得了段级别的锁定。因此你是对的。即第二次插入等到第一次插入完成
答案 4 :(得分:0)
看看javadoc for ConcurrentMap。它描述了可用于处理并发映射突变的额外方法。