2

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

我在一本书中发现了这样的内容:

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 和可能的 put 原子化:

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() 结果无效?

干杯奥利弗

4

2 回答 2

3

没有必要。

确实,以下代码不会是线程安全的,因为cache.get()可能会被另一个线程无效。

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

但是,代码只是为了优化(原子操作更昂贵)。原子性由map.putIfAbsent()哪个是原子的,因此是线程安全的。然而,如果cache.get()返回其他东西 then null,昂贵的原子操作不会执行。

于 2013-08-21T14:57:30.227 回答
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

于 2018-04-04T13:41:38.387 回答