并发hashMap putIfAbsent方法功能

时间:2013-04-06 12:13:02

标签: java concurrenthashmap

我是java世界的新bie并探索并发哈希映射,在探索并发hashmap API时,我发现了putifAbsent()方法

public V putIfAbsent(K paramK, V paramV)
  {
    if (paramV == null)
      throw new NullPointerException();
    int i = hash(paramK.hashCode());
    return segmentFor(i).put(paramK, i, paramV, true);
  }

现在请告知它的功能是什么,我们什么时候需要它,如果可能的话请用一个简单的例子来解释。

3 个答案:

答案 0 :(得分:12)

ConcurrentHashMap的设计使其可以被大量并发Thread使用。

现在,如果你使用标准Map接口提供的方法,你可能会写这样的东西

  if(!map.containsKey("something")) {
      map.put("something", "a value");
  }

这看起来不错,似乎可以胜任,但它不是线程安全的。所以你会想,“啊,但我知道synchronized关键字”并将其改为此

  synchronized(map) {
      if(!map.containsKey("something")) {
          map.put("something", "a value");
      }
  }

解决了这个问题。

现在你所做的是锁定整个地图以便读取和写入,同时检查密钥是否存在,然后将其添加到地图中。

这是一个非常粗糙的解决方案。现在,您可以使用双重检查锁实现自己的解决方案并重新锁定密钥等,但很多 非常复杂的代码非常容易出错。

因此,您使用JDK提供的解决方案。

ConcurrentHashMap是一个聪明的实现,它将Map分成区域并单独锁定它们,这样您就可以在没有外部锁定的情况下对映射进行并发,线程安全,读写。

与实现中的所有其他方法一样,putIfAbsent锁定密钥的区域而不是整个Map,因此允许其他区域同时继续进行其他操作。

答案 1 :(得分:0)

当多个线程可以同时访问同一个映射时,使用ConcurrentHashMap。在这种情况下,手动实现putIfAbsent(),如下所示:

if (!map.containsKey(key)) {
    map.put(key, value);
} 

实际上,两个线程可以并行执行上面的块并进入竞争条件,其中两个都首先测试密钥是否不存在,然后两者都将它们自己的值放在映射中,从而打破了程序的不变量。

ConcurrentHashMap因此提供putIfAbsent()操作,确保以原子方式完成,避免竞争条件。

答案 2 :(得分:0)

想象一下,我们需要一个懒惰初始化的命名单例bean的缓存。下面是基于ConcurrentHashMap的无锁实现:

ConcurrentMap<String, Object> map = new ConcurrentHashMap<>();

<T> T getBean(String name, Class<T> cls) throws Exception {
    T b1 = (T) map.get(name);
    if (b1 != null) {
        return b1;
    }
    b1 = cls.newInstance();
    T b2 = (T) map.putIfAbsent(name, b1);
    if (b2 != null) {
        return b2;
    }
    return b1;
}

请注意,它解决了与双重检查锁定相同的问题,但没有锁定。