ConcurrentMap的putIfAbsent与put的区别

     首先putIfAbsent与put都可以往map中添加内容,但它们在添加的时候有着很大的不同,一不注意,就会采坑。putIfAbsent在添加的时候会验证hash值,如果hash值一样,则不会更新value;但put不管hash值是否一样,每次都会更新!

比如:

static ConcurrentMap lineMap = new ConcurrentHashMap();
	
	public static void main(String[] args) {
		BusLine bl = new BusLine();
		bl.setLineName("1");
		bl.setLineId(1);
		lineMap.putIfAbsent(bl.getLineId(), bl);
		System.out.println(lineMap);
		BusLine b21 = new BusLine();
		b21.setLineId(1);
		b21.setLineName("21");
		lineMap.putIfAbsent(b21.getLineId(), b21);
		System.out.println(lineMap);
		
		BusLine b3 = new BusLine();
		b3.setLineId(1);
		b3.setLineName("3");
		lineMap.put(b3.getLineId(), b3);
		System.out.println(lineMap);
		BusLine b4 = new BusLine();
		b4.setLineId(1);
		b4.setLineName("4");
		lineMap.put(b3.getLineId(), b4);
		System.out.println(lineMap);
	}

对于上面的这段代码:它的执行结果是:

{1=BusLine [Hash = 1395089624,  lineName=1,]}
{1=BusLine [Hash = 1395089624,  lineName=1,]} 
{1=BusLine [Hash = 1476011703,  lineName=3,]} 
{1=BusLine [Hash = 1603195447,  lineName=4,]}

可以看出,使用putIfAbsent更新BusLine 时并没有成功,但使用put时成功了!那这是什么原因了,用hash值可以看出,b1和b21的hash值是一样的,所以不会更新value值!可是明明我们new 了2个BusLine呀!那为什么hash会一样呢?

那我们打印一下这四个对象的hash值:

System.out.println("bl.hashCode ="+bl.hashCode());
		System.out.println("b2l.hashCode ="+b21.hashCode());
		System.out.println("b3.hashCode ="+b3.hashCode());
		System.out.println("b4.hashCode ="+b4.hashCode());
bl.hashCode =1395089624
b2l.hashCode =792791759
b3.hashCode =1476011703
b4.hashCode =1603195447

我们发现这hash值是不一样的呀,那为什么map中是一样的呢?原因是得看源码:

putIfAbsent的源码如下:

public V putIfAbsent(K key, V value) {
    Segment s;
    if (value == null)
        throw new NullPointerException();
    int hash = hash(key);
    int j = (hash >>> segmentShift) & segmentMask;
    if ((s = (Segment)UNSAFE.getObject
         (segments, (j << SSHIFT) + SBASE)) == null)
        s = ensureSegment(j);
    return s.put(key, hash, value, true);
}

put的原码如下:

public V put(K key, V value) {
      Segment s;
      if (value == null)
          throw new NullPointerException();
      int hash = hash(key);
      int j = (hash >>> segmentShift) & segmentMask;
      if ((s = (Segment)UNSAFE.getObject          // nonvolatile; recheck
           (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
          s = ensureSegment(j);
      return s.put(key, hash, value, false);
  }
可以看出区别是: s.put(key, hash, value,  true ); 和s.put(key, hash, value, false) 也就是说 onlyIfAbsent为true的情况下才会更新!

而onlyIfAbsent为true的情况就是map中存在可以的情况。







你可能感兴趣的:(java)