ConcurrentHashMap源码分析

本文深入剖析了ConcurrentHashMap的put方法实现原理,包括数组初始化、CAS插入、帮助扩容、链表转红黑树等核心流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇是自己对ConcurrentHashMap某些源码的一些分析。

put方法

public V put(K key, V value) {
   	return putVal(key, value, false);
}

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
		//不允许插入null键
	   if (key == null || value == null) throw new NullPointerException();
	   int hash = spread(key.hashCode());
	   int binCount = 0;
	   for (Node<K,V>[] tab = table;;) {
	       Node<K,V> f; int n, i, fh; K fk; V fv;
	       //Node数组为空则进行数组初始化
	       if (tab == null || (n = tab.length) == 0)
	           tab = initTable();
			//如果数组对应位置没有值,就进行cas添加,失败就进行break,注意求位置用了与操作
	       else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
	           if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
	               break;                   // no lock when adding to empty bin
	       }
	       //如果此位置元素已经存在,且处于被移动元素状态,就协助扩容
	       else if ((fh = f.hash) == MOVED)
	           tab = helpTransfer(tab, f);
	       //不进入此块。因为put方法中onlyIfAbsent传入为false
	       else if (onlyIfAbsent // check first node without acquiring lock
	                && fh == hash
	                && ((fk = f.key) == key || (fk != null && key.equals(fk)))
	                && (fv = f.val) != null)
	           return fv;
	       //发生hash碰撞,就锁注此位置的链表或红黑树
	       else {
	           V oldVal = null;
	           synchronized (f) {
	           //如果此位置是 链表 的头结点。
	           //f是此位置头结点,i是通过hash求出的元素位置,求法见第一个else if那里的条件
	               if (tabAt(tab, i) == f) {
	                   if (fh >= 0) {
	                       binCount = 1;
	                       for (Node<K,V> e = f;; ++binCount) {
	                           K ek;
	                           //若存在此节点,就更新value值
	                           if (e.hash == hash &&
	                               ((ek = e.key) == key ||
	                                (ek != null && key.equals(ek)))) {
	                               oldVal = e.val;
	                               if (!onlyIfAbsent)
	                                   e.val = value;
	                               break;
	                           }
	                           //如果到了最后一个节点仍然找不到相同的,就添加在链表后面
	                           Node<K,V> pred = e;
	                           if ((e = e.next) == null) {
	                               pred.next = new Node<K,V>(hash, key, value);
	                               break;
	                           }
	                       }
	                   }
	                   //如果此位置是 红黑树 的头结点,进行添加操作
	                   else if (f instanceof TreeBin) {
	                       Node<K,V> p;
	                       binCount = 2;
	                       if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
	                                                      value)) != null) {
	                           oldVal = p.val;
	                           if (!onlyIfAbsent)
	                               p.val = value;
	                       }
	                   }
	                   //若f是保留节点,就抛出更新异常
	                   else if (f instanceof ReservationNode)
	                       throw new IllegalStateException("Recursive update");
	               }
	           }
	           //若链表长度到达临界值,就转为红黑树
	           if (binCount != 0) {
	               if (binCount >= TREEIFY_THRESHOLD)
	                   treeifyBin(tab, i);
	               if (oldVal != null)
	                   return oldVal;
	               break;
	           }
	       }
	   }
	   addCount(1L, binCount);
	   return null;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值