将 putIfAbsent 合并为 ConcurrentMap 替换

我有一个用例,我必须

  • 如果 ConcurrentHashMap 中不存在该键,则插入新值
  • 如果 ConcurrentHashMap 中已存在键,则将旧值替换为新值,其中新值派生自旧值(不是昂贵的操作)

我有以下代码可以提供:

public void insertOrReplace(String key, String value) {
        boolean updated = false;
        do {
            String oldValue = concurrentMap.get(key);
            if (oldValue == null) {
                oldValue = concurrentMap.putIfAbsent(key, value);
                if (oldValue == null) {
                    updated = true;
                }
            }
            if (oldValue != null) {
                final String newValue = recalculateNewValue(oldValue, value);
                updated = concurrentMap.replace(key, oldValue, newValue);
            }
        } while (!updated);
    }

你认为它是正确的和线程安全的吗?

有没有更简单的方法?


答案 1

您可以使用下面的代码使其更短一些,该代码相当于您的代码。我已经对它进行了一些压力测试,有数千个线程同时访问它:它按预期工作,执行了许多重试(循环)(显然,你永远无法通过并发世界中的测试来证明正确性)。

public void insertOrReplace(String key, String value) {
    for (;;) {
        String oldValue = concurrentMap.putIfAbsent(key, value);
        if (oldValue == null)
            return;

        final String newValue = recalculateNewValue(oldValue, value);
        if (concurrentMap.replace(key, oldValue, newValue))
            return;
    }
}

答案 2

您的方法似乎是线程安全的。如果您不需要 ConcurrentHashMap 的性能优势,请考虑改用常规 HashMap 并同步对它的所有访问。你的方法类似于AtomicInteger.getAndSet(int),所以它应该没问题。我怀疑有没有更简单的方法可以做到这一点,除非你正在寻找一个图书馆电话来为你完成工作。


推荐