20

Java Docs说,putIfAbsent相当于

   if (!map.containsKey(key)) 
      return map.put(key, value);
   else
      return map.get(key);

因此,如果该键存在于地图中,它不会更新其值。它是否正确?

如果我想根据某些标准更新键值怎么办?说到期时间等。

这会是添加和更新缓存的更好实现吗?

public void AddToCache(T key, V value)
{
   V local = _cache.putifabsent(key, value);

   if(local.equals(value) && local.IsExpired() == false){
     return;
   }
   // this is for updating the cache with a new value
   _cache.put(key, value);
}
4

2 回答 2

13

所以它不会更新键的值。它是否正确?

那是对的。它将返回地图中已经存在的当前值。

这会是添加和更新缓存的更好实现吗?

有几件事可以使您的实施更好。

1.你不应该使用 putIfAbsent 来测试它是否存在,你应该只在你想确保一个不存在时才使用它 then putIfAbsent。相反,您应该使用map.get它来测试它的存在(或 map.contains)。

    V local = _cache.get(key);
    if (local.equals(value) && !local.IsExpired()) {
        return;
    }

2.而不是 put 您将要替换,这是因为可能会发生竞争条件,其中if两个或多个线程可以将其评估为假,其中两个(或多个)线程中的一个将覆盖另一个线程的 put。

你可以做的是替换

当一切都说完了,它可能看起来像这样

public void AddToCache(T key, V value) {
    for (;;) {

        V local = _cache.get(key);
        if(local == null){
            local = _cache.putIfAbsent(key, value);
            if(local == null)
                return;
        }
        if (local.equals(value) && !local.IsExpired()) {
            return;
        }

        if (_cache.replace(key, local, value))
            return;
    }
}
于 2012-05-07T17:40:02.387 回答
4

如果密钥以前不在地图中,您的代码将引发 NPE。

除此之外,虽然这是一个合理的想法,但它不会在“并发”环境中工作。添加该putIfAbsent()方法的原因是,映射可以使用它用来使操作线程安全的任何底层支持来管理操作的原子性。在您的实现中,两个不同的调用者可能会互相踩踏结束(第一个用新值替换过期值,第二个立即用第二个新值替换第一个新值)。

于 2012-05-07T17:39:43.187 回答