使用ConcurrentHashMap缓存

CCC*_*CCC 8 java collections concurrency multithreading hashmap

我有以下代码:

public class Cache {

    private final Map map = new ConcurrentHashMap();

    public Object get(Object key) {

        Object value = map.get(key);
        if (value == null) {
            value = new SomeObject();
            map.put(key, value);
        }

        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:地图putget方法是线程安全的,但由于整个块未同步 - 多个线程可以两次添加相同的密钥吗?

Mur*_*nik 9

put并且get在某种意义上是线程安全的,即从不同的线程调用它们不能破坏数据结构(例如,可以正常java.util.HashMap).

但是,由于块未同步,您可能仍有多个线程添加相同的密钥:两个线程都可以通过null检查,一个添加密钥并返回其值,然后第二个将使用新的值覆盖该值并返回它.


小智 7

从Java 8开始,您还可以使用以下方法防止添加重复的键:

public class Cache {

    private final Map map = new ConcurrentHashMap();

    public Object get(Object key) {

        Object value = map.computeIfAbsent(key, (key) -> {
          return new SomeObject();
        });

        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

API文档状态:

如果指定的键尚未与某个值关联,则尝试使用给定的映射函数计算其值,除非为null,否则将其输入此映射。整个方法调用是原子执行的,因此每个键最多只能应用一次该功能。在进行计算时,可能会阻止其他线程在此映射上进行的某些尝试的更新操作,因此计算应简短而简单,并且不得尝试更新此映射的任何其他映射。