简体   繁体   English

ConcurrentHashMap put vs putIfAbsent

[英]ConcurrentHashMap put vs putIfAbsent

Java Docs says that, putIfAbsent is equivalent to Java Docs说, putIfAbsent相当于

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

So if the key exists in the map, it doesn't update its value. 因此,如果密钥存在于地图中,则不会更新其值。 Is this correct? 它是否正确?

What if i want to update a keys value based on some criteria? 如果我想根据某些条件更新密钥值怎么办? Say expiration time etc. 说过期时间等

Would this be a better impl for adding and updating cache? 这是否是添加和更新缓存的更好的方法?

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

So it doesnt update a key's value. 所以它不会更新密钥的价值。 is this correct? 它是否正确?

That is correct. 那是正确的。 It will return the current value that was already in the Map. 它将返回Map中已有的当前值。

would this be a better impl for adding and updating cache? 这是添加和更新缓存的更好的方法吗?

A couple things would make your implementation better. 一些事情会使您的实施更好。

1. You shouldn't use putIfAbsent to test if it exists, you should only use it when you want to ensure if one does not exist then putIfAbsent . 1.你不应该使用putIfAbsent来测试它是否存在,你应该只在你想要确保一个不存在时使用它然后putIfAbsent Instead you should use map.get to test it's existence (or map.contains). 相反,你应该使用map.get来测试它的存在(或map.contains)。

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

2. Instead of put you will want to replace, this is because a race condition can occur where the if can be evaluated as false by two or more threads in which one of the two (or more) threads will overwrite the other thread's puts. 2.而不是放置你想要替换,这是因为可能发生竞争条件,其中if可以被两个或多个线程评估为false,其中两个(或更多)线程中的一个将覆盖其他线程的puts。

What you can do instead is replace 你能做的就是替换

When all is said and done it could look like this 完成所有操作后,它可能看起来像这样

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

Your code will throw an NPE if the key was not previously in the map. 如果密钥以前不在地图中,您的代码将抛出NPE。

Other than that, although this is a reasonable idea, it will not work in a " concurrent " environment. 除此之外,虽然这是一个合理的想法,但它不适用于“ 并发 ”环境。 The reason the putIfAbsent() method was added was so that the map could manage the atomicity of the operation using whatever underlying support it is using to make the operations thread-safe. 添加putIfAbsent()方法的原因是,映射可以使用它用于使操作线程安全的任何底层支持来管理操作的原子性。 In your implementation, 2 different callers could end of stepping on each other (the first replaces an expired value with a new one, and the second immediately replaces the first new one with a second new one). 在您的实现中,2个不同的调用者可能会相互踩踏(第一个用新值替换过期值,第二个立即用第二个新值替换第一个新值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM