ConcurrentHashMap的putIfAbsent方法详解与应用_元一软件
在并发编程中ConcurrentHashMap是一个常用的线程安全哈希表实现它提供了多种原子操作方法来简化并发环境下的数据更新。其中putIfAbsent方法是一个简单而强大的工具用于在键不存在时插入值键存在时则不执行任何操作。本文将详细解析putIfAbsent方法的作用、用法、源码逻辑以及与其他相关方法的对比。putIfAbsent方法的作用putIfAbsent方法用于在键不存在时原子性地插入值键存在时则不执行任何操作。这对于需要避免重复插入或初始化的场景非常有用。方法定义V putIfAbsent(K key, V value)参数key要检查的键。value若键不存在时插入的值。返回值返回键之前关联的值若键不存在则返回null。核心特性原子性检查键是否存在和插入值的操作是原子的避免并发冲突。条件插入仅当键不存在时插入值否则忽略操作。无函数计算值需提前创建可能引发多余对象创建与computeIfAbsent对比。典型使用场景简单缓存系统ConcurrentHashMapString, ConfigconfigCachenew ConcurrentHashMap();public Config getConfig(String configName){Config confignew Config(configName);// 可能创建多余对象 Config existingconfigCache.putIfAbsent(configName, config);returnexisting!null ? existing:config;}避免重复初始化ConcurrentHashMapString, ListStringlistCachenew ConcurrentHashMap();public ListStringgetList(String key){ListStringlistnew ArrayList();ListStringexistinglistCache.putIfAbsent(key, list);returnexisting!null ? existing:list;}源码逻辑简化final V putIfAbsent(K key, V value){if(keynull||valuenull)throw new NullPointerException();inthashspread(key.hashCode());for(NodeK,V[]tabtable;;){NodeK,Vf;int n, i, fh;if(tabnull||(ntab.length)0)tabinitTable();elseif((ftabAt(tab,i(n-1)hash))null){// 键不存在尝试插入新节点if(casTabAt(tab, i, null, new NodeK,V(hash, key, value, null)))break;}elseif((fhf.hash)MOVED)tabhelpTransfer(tab,f);//协助扩容 else { V oldValnull;synchronized(f){//锁住当前桶的头节点 if(tabAt(tab,i)f){//遍历链表或红黑树查找键 for(NodeK,Vef;;){ if(e.hashhash((eke.key)key||key.equals(ek))){oldVale.val;break;}if((ee.next)null)break;}if(oldValnull){// 键不存在插入新节点 addNode(tab, hash, key, value, i);}}}if(oldVal!null)returnoldVal;}}addCount(1L, binCount);returnnull;}与computeIfAbsent对比特性putIfAbsentcomputeIfAbsent触发条件键不存在键不存在或值为null值创建时机调用前创建可能多余函数内按需创建函数参数无FunctionK, V适用场景对象创建成本低、简单插入延迟初始化、复杂对象创建最佳实践避免多余对象创建若对象创建成本高优先使用computeIfAbsent。// 不推荐可能创建多余对象 Value objnew Value();map.putIfAbsent(key, obj);// 推荐按需创建 map.computeIfAbsent(key, k -new Value());明确返回值含义返回值null可能表示键不存在或原值为null需结合业务逻辑处理。完整示例importjava.util.concurrent.ConcurrentHashMap;public class PutIfAbsentDemo{public static void main(String[]args){ConcurrentHashMapString, Integercachenew ConcurrentHashMap();// 插入键值对键不存在 Integer oldValuecache.putIfAbsent(a,1);System.out.println(Old value for a: oldValue);// 输出: null // 尝试插入已存在的键 oldValuecache.putIfAbsent(a,2);System.out.println(Old value for a: oldValue);// 输出:1System.out.println(Current value for a: cache.get(a));// 输出:1}}

相关新闻