ConcurrentHashMap作为缓存

时间:2013-08-21 14:36:01

标签: java caching thread-safety concurrenthashmap

如果将ConcurrentHashMap用作map我问自己,实现线程安全的正确方法是什么?

在一本书中我发现了这样的东西:

private ConcurrentHashMap<KEY, VALUE> cache = new ConcurrentHashMap<>();

public V put(KEY key, VALUE value) {
    VALUE ret = cache.get(key);
    if (ret == null) {
        ret = cache.putIfAbsent(key, value);
        if (ret == null) {
            ret = value;
        }
    }
    return ret;
}

现在我问自己是不是有必要让get和可能的原子像这样:

public V put(KEY key, VALUE value) {
    synchronized(cache) {
        VALUE ret = cache.get(key);
        if (ret == null) {
            ret = cache.putIfAbsent(key, value);
            if (ret == null) {
                ret = value;
            }
        }
    }
    return ret;
}

因为当cache.get()返回null时,另一个线程可能会使第一个线程的cache.get()结果无效?

干杯 奥利弗

2 个答案:

答案 0 :(得分:3)

没有必要。

以下代码由于cache.get()而导致的线程不安全,可能会被另一个线程无效。

VALUE ret = cache.get(key);
if (ret == null) {...}

但是,代码仅用于优化(原子操作更昂贵)。原子性由map.putIfAbsent()确保,它是原子的,因此是线程安全的。然而,如果cache.get()返回其他内容然后null,那么昂贵的原子操作就不会执行。

答案 1 :(得分:0)

您可以在同步块中使用延迟初始化。

    private static volatile ConcurrentHashMap<KEY, VALUE> cache = null;

    public static ConcurrentHashMap<KEY, VALUE> getCacheInstance() {
        if (cache == null) {
            synchronized(cache) {
                if (cache == null) {
                    cache = new ConcurrentHashMap<>();
                }
            }
        }
        return cache ;
    }

    public static put(ConcurrentHashMap<KEY, VALUE> cache) {
        VALUE ret = cache.get(KEY);
        if (ret == null) {...
        }     
    }

在Java 8中,实现本地线程安全缓存非常容易。

    private static final ConcurrentMap<KEY, VALUE> cache = 
                                          new ConcurrentHashMap();

    public Object get(String KEY) {
       return cache.computeIfAbsent(KEY, k - > createObject(k));
    }

您可以在Java 7中使用双重检查线程安全性来实现它。

    public Object get(String KEY) {
        if (!cache.containsKey(KEY)) {
            synchronized (cache) {
               if (!cache.containsKey(KEY)) {
                   cache.put(KEY, createObject(KEY));
               }
            }
        }
        return cache.get(KEY);
    }

https://developer-should-know.com/post/116472734172/local-thread-safe-cache-with-java