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()which はアトミックであるため、スレッドセーフであるため、原子性が保証されます。それにもかかわらず、cache.get()何か他のものを返す場合null、高価なアトミック操作は実行されません。

于 2013-08-21T14:57:30.227 に答える