概述
1.简述
在JAVA8的Map接口中,增加了一个方法computeIfAbsent,此方法签名如下:
public V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
如果mappingFunction(key)返回的值为null或抛出异常,则不会有记录存入map
此方法首先判断缓存MAP中是否存在指定key的值,如果不存在,会自动调用mappingFunction(key)计算key的value,然后将key = value放入到缓存Map。
ConcurrentHashMap中重写了computeIfAbsent 方法确保mappingFunction中的操作是线程安全的。
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
if (key == null || mappingFunction == null)
throw new NullPointerException();
int h = spread(key.hashCode());
V val = null;
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
Node<K,V> r = new ReservationNode<K,V>();
synchronized (r) {
if (casTabAt(tab, i, null, r)) {
binCount = 1;
Node<K,V> node = null;
try {
if ((val = mappingFunction.apply(key)) != null)
node = new Node<K,V>(h, key, val, null);
} finally {
setTabAt(tab, i, node);
}
}
}
if (binCount != 0)
break;
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
boolean added = false;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek; V ev;
if (e.hash == h &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
val = e.val;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
if ((val = mappingFunction.apply(key)) != null) {
added = true;
pred.next = new Node<K,V>(h, key, val, null);
}
break;
}
}
}
else if (f instanceof TreeBin) {
binCount = 2;
TreeBin<K,V> t = (TreeBin<K,V>)f;
TreeNode<K,V> r, p;
if ((r = t.root) != null &&
(p = r.findTreeNode(h, key, null)) != null)
val = p.val;
else if ((val = mappingFunction.apply(key)) != null) {
added = true;
t.putTreeVal(h, key, val);
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (!added)
return val;
break;
}
}
}
if (val != null)
addCount(1L, binCount);
return val;
}
2.使用方法
可以将原始代码为:
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
Client esClient = map.get("key");
if (esClient == null) {
//防止启动时高并发导致创建多个client
synchronized (ClientUtil.class) {
esClient = map.get("key");
if (esClient == null) {
//初始化操作
esClient = new Client();
}
}
}
使用computeIfAbsent 代替:
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.computeIfAbsent("key",()->{
//初始化操作
return new Client();
});
注:mappingFunction方法的结果会作为值直接插入到map中,无需在mappingFunction中再执行put。
3.风险
不能在ConcurrentHashMap.computeIfAbsent方法中进行递归调用,及在mappingFunction方法中不能在进行put相关的操作会造成死循环。
例如:
public static void main(String[] args) {
Map<String, Integer> map = new ConcurrentHashMap<>(16);
map.computeIfAbsent("AaAa", key -> {
return map.computeIfAbsent("BBBB", key2 -> 42);
});
System.out.println(map.size());
}
This is fixed in JDK 9 with JDK-8071667 . When the test case is run in JDK 9-ea, it gives a ConcurrentModification Exception.
https://bugs.openjdk.java.net/browse/JDK-8172951
好在这个问题在java 1.9中已经基本修复了。
java 9
引用:
https://blog.csdn.net/qq_16998379/article/details/90719502
https://www.imooc.com/article/68332
https://www.jianshu.com/p/59bd27e137e1
最后
以上就是阔达超短裙为你收集整理的JAVA8 ConcurrentHashMap.computeIfAbsent 的使用及说明的全部内容,希望文章能够帮你解决JAVA8 ConcurrentHashMap.computeIfAbsent 的使用及说明所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复