并发 hashmap 同时插入
Concurrent hashmap simultaneous insertion
我读到在 Java 的并发 hashmap 中,同时插入是可能的,因为它被分成段并且为每个段采用单独的锁。
但是如果两个插入将发生在同一个段上,那么这些同时发生就不会发生。
我的问题是在这种情况下会发生什么?第二次插入会等到第一次插入完成还是什么?
看看javadoc for ConcurrentMap。它描述了可用于处理并发映射突变的额外方法。
如果 2 个更新试图在同一个网段上发生,它们将相互争用,其中一个将不得不等待。您可以通过选择一个 concurrencyLevel 值来优化这一点,该值考虑了将同时更新 hashmap 的线程数。
中找到所有详细信息
一般来说,您不必太在意 ConcurrentHashMap
是如何实现的。它只是遵守 ConcurrentMap
的约定,确保并发修改是可能的。
但要回答您的问题:是的,一个插入可能会等待另一个插入完成。在内部,它使用锁来确保一个线程正在等待另一个线程释放锁。 Class 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;
}
这可以给你一个想法。
大多数并发数据结构的启发式方法是首先修改后备数据结构,以及外部方法可见的前置数据结构。然后,当修改完成后,后台数据结构成为public数据结构,public数据结构被推到后面。远不止于此,但这是典型的合同。
ConcurrentHashMap 包含 Segment 数组,Segment 数组又包含 HashEntry 数组。每个 HashEntry 都包含一个键、一个值和一个指向它的下一个相邻条目的指针。
但是它获取的是段级别的锁。因此你是对的。即第二次插入等到第一个完成
我读到在 Java 的并发 hashmap 中,同时插入是可能的,因为它被分成段并且为每个段采用单独的锁。 但是如果两个插入将发生在同一个段上,那么这些同时发生就不会发生。 我的问题是在这种情况下会发生什么?第二次插入会等到第一次插入完成还是什么?
看看javadoc for ConcurrentMap。它描述了可用于处理并发映射突变的额外方法。
如果 2 个更新试图在同一个网段上发生,它们将相互争用,其中一个将不得不等待。您可以通过选择一个 concurrencyLevel 值来优化这一点,该值考虑了将同时更新 hashmap 的线程数。
中找到所有详细信息一般来说,您不必太在意 ConcurrentHashMap
是如何实现的。它只是遵守 ConcurrentMap
的约定,确保并发修改是可能的。
但要回答您的问题:是的,一个插入可能会等待另一个插入完成。在内部,它使用锁来确保一个线程正在等待另一个线程释放锁。 Class 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;
}
这可以给你一个想法。
大多数并发数据结构的启发式方法是首先修改后备数据结构,以及外部方法可见的前置数据结构。然后,当修改完成后,后台数据结构成为public数据结构,public数据结构被推到后面。远不止于此,但这是典型的合同。
ConcurrentHashMap 包含 Segment 数组,Segment 数组又包含 HashEntry 数组。每个 HashEntry 都包含一个键、一个值和一个指向它的下一个相邻条目的指针。
但是它获取的是段级别的锁。因此你是对的。即第二次插入等到第一个完成