ConcurrentHashMap put vs putIfAbsent

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); } 

所以它不会更新密钥的价值。 它是否正确?

那是正确的。 它将返回Map中已存在的当前值。

这是添加和更新缓存的更好的方法吗?

一些事情会使您的实施更好。

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

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

2.而不是放置你想要替换,这是因为可能发生竞争条件,其中if可以被两个或多个线程评估为false,其中两个(或更多)线程中的一个将覆盖其他线程的puts。

你可以做的是替换

当所有的事情都说完了,它可能看起来像这样

 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; } } 

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

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