并发 hashmap 同时插入

Concurrent hashmap simultaneous insertion

我读到在 Java 的并发 hashmap 中,同时插入是可能的,因为它被分成段并且为每个段采用单独的锁。 但是如果两个插入将发生在同一个段上,那么这些同时发生就不会发生。 我的问题是在这种情况下会发生什么?第二次插入会等到第一次插入完成还是什么?

看看javadoc for ConcurrentMap。它描述了可用于处理并发映射突变的额外方法。

如果 2 个更新试图在同一个网段上发生,它们将相互争用,其中一个将不得不等待。您可以通过选择一个 concurrencyLevel 值来优化这一点,该值考虑了将同时更新 hashmap 的线程数。

您可以在 javadoc for the class

中找到所有详细信息

一般来说,您不必太在意 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;
}

这可以给你一个想法。

ConcurrentHashMap does not block when performing retrieval operations, and there is no locking for the usual operations

大多数并发数据结构的启发式方法是首先修改后备数据结构,以及外部方法可见的前置数据结构。然后,当修改完成后,后台数据结构成为public数据结构,public数据结构被推到后面。远不止于此,但这是典型的合同。

ConcurrentHashMap 包含 Segment 数组,Segment 数组又包含 HashEntry 数组。每个 HashEntry 都包含一个键、一个值和一个指向它的下一个相邻条目的指针。

但是它获取的是段级别的锁。因此你是对的。即第二次插入等到第一个完成