首先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中存在可以的情况。