java - ConcurrentHashMap:将集合存储为值时需要同步

标签 java multithreading concurrenthashmap

我有一些使用 ConcurrentHashMap 的代码并想确认我所做的一切是否正确。

映射将字符串存储为键,将集合 ( Set ) 作为值。我最初有一个实现,我将使用锁 strip 模式以原子方式执行一些操作(放置、删除等),但后来意识到我可以使用 computeIfAbsent/putIfAbsent 来代替它。 (对于看跌期权)和 computeIfAbsent (用于删除)。多个线程调用所有 4 个方法(get、put、removeKey、removeValue)。

谁能告诉我我的 AFTER 代码是否正确且线程安全?提前致谢!

private final ConcurrentMap<K, Set<V>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<K, Object> locks = new ConcurrentHashMap<>();

public Set<V> getValue(K key) {
    if (map.get(key) == null) return null;
    return map.get(key).stream().map(k -> k.getValue()).collect(Collectors.toSet());
}

之前

private void putValue(K key, V value) {
        Object lock = locks.putIfAbsent(key, new Object());
    if (lock == null) lock = locks.get(key);
        Set<V> existingSet = map.computeIfAbsent(key, k -> {
            Set<V> values = new ConcurrentSkipListSet<>(MY_COMPARATOR);
            values.add(value);
            return values;
        });
        if (existingSet != null) { // <- my guess is that this is unnecessary
            synchronized (lock) {
                map.get(key).add(expiringValue);
            }
        }
    }

public void removeKey(K key) {
    if (key == null) return;
    if (map.get(key) != null) {
        Object lock = locks.get(key);
        synchronized (lock) {
            map.remove(key);
        }
        locks.remove(key);
    }
}

public void removeValue(K key, V value) {
    if (key == null || value == null) return;
    if (map.get(key) != null) {
        Object lock = locks.get(key);
        synchronized (lock) {
            map.get(key).remove(value);
            if (map.get(key).size() == 0) {
                map.remove(key);
            }
        }
    }
}

之后

private void putValue(K key, V value) {
    map.computeIfAbsent(key, k -> new ConcurrentSkipListSet<>(MY_COMPARATOR)).add(value);
}

public void removeKey(K key) {
    map.remove(key);
}

public void removeValue(K key, V value) {
    Set<ExpiringValue<V>> resultingValues = map.computeIfPresent(key, (k, values) -> {
        values.remove(value);
        return values;
    });
    if (resultingValues != null && resultingValues.size() == 0) {
        map.remove(key);
    }
}

最佳答案

至少一个可能的问题是您可能会丢失 putValue 的值。 computeIfAbsent 是线程安全的,但 add() 不再是线程安全的。因此,您可以(取决于您的逻辑)提出以下场景:

T1: computeIfAbsent creates the set for key K
T2: removes K
T1: performs add on the set, which is no longer in the map

关于java - ConcurrentHashMap:将集合存储为值时需要同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44854553/

相关文章:

java - ConcurrentHashMap迭代保证

java - 我在自己的 LinkedList 类中引用我的 'head' 节点时遇到问题

java - 使用java将XML文件转换为CSV文件(具有多个元素值)

java - 无法连接到端口 7056 上的二进制 FirefoxBinary(C :\Program Files (x86)\Mozilla Firefox\firefox. exe);处理输出如下: null

multithreading - Twisted:同时使用多个线程和进程

python - 当 QThread() 停止运行时(Python),我是否需要手动调用 .quit() 方法?

java - 我想将 computeIfPresent 和 putIfAbsent 都放到一个原子函数中

java - 如何从多个线程填充并发 HashMap ?

java - 当辅助消息应用查看消息时关闭默认消息应用的通知

python - 在主线程的线程中引发未处理的异常?