ConcurrentHashMap

1.put方法

1.初始化,2.扩容,3.数据迁移

先判断数组table是否为null或空,是初始化;

存放当前元素的位置为空,一次CAS操作放入(不需要加锁);

当前table数组是否在扩容状态,是迁移数据

非空,给头节点加锁,判断是链表还是红黑树,放入值;

判断是否要转换为红黑树

 

复制代码
 1 public V put(K key, V value) {
 2         return putVal(key, value, false);
 3     }
 4  
 5     /** Implementation for put and putIfAbsent */
 6     final V putVal(K key, V value, boolean onlyIfAbsent) {
 7         //key和value都不允许null
 8         if (key == null || value == null) throw new NullPointerException();
 9         int hash = spread(key.hashCode());
10         // 用于记录相应链表的长度
11         int binCount = 0;
12         //遍历数组
13         for (Node<K,V>[] tab = table;;) {
14             Node<K,V> f; int n, i, fh;
15             //数组不存在或者没数据的情况,初始化
16             if (tab == null || (n = tab.length) == 0)
17                 tab = initTable();
18             //如果数组当前位置为null,用一次 CAS 操作将这个新值放入其中  
19             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
20                 if (casTabAt(tab, i, null,
21                              new Node<K,V>(hash, key, value, null)))
22                     break;                   // no lock when adding to empty bin
23             }
24             //
25             else if ((fh = f.hash) == MOVED)
26                 tab = helpTransfer(tab, f);
27             else {
28                 //如果f是头结点
29                 V oldVal = null;
30                 //加锁
31                 synchronized (f) {
32                     //
33                     if (tabAt(tab, i) == f) {
34                         //头结点的 hash 值大于 0,说明是链表
35                         if (fh >= 0) {
36                             //链表长度+1
37                             binCount = 1;
38                             //遍历链表
39                             for (Node<K,V> e = f;; ++binCount) {
40                                 K ek;
41                                 if (e.hash == hash &&
42                                     ((ek = e.key) == key ||
43                                      (ek != null && key.equals(ek)))) {
44                                     // 如果发现了"相等"的 key,判断是否要进行值覆盖
45                                     oldVal = e.val;
46                                     if (!onlyIfAbsent)
47                                         e.val = value;
48                                     break;
49                                 }
50                                 // 到了链表的最末端,将新值放到链表的最末端
51                                 Node<K,V> pred = e;
52                                 if ((e = e.next) == null) {
53                                     pred.next = new Node<K,V>(hash, key,
54                                                               value, null);
55                                     break;
56                                 }
57                             }
58                         }
59                         //如果是一个红黑树的结构,将新值放到红黑树
60                         else if (f instanceof TreeBin) {
61                             Node<K,V> p;
62                             binCount = 2;
63                             if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
64                                                            value)) != null) {
65                                 oldVal = p.val;
66                                 if (!onlyIfAbsent)
67                                     p.val = value;
68                             }
69                         }
70                     }
71                 }
72                 //链表的长度大于8;转换为红黑树
73                 if (binCount != 0) {
74                     if (binCount >= TREEIFY_THRESHOLD)
75                         treeifyBin(tab, i);
76                     if (oldVal != null)
77                         return oldVal;
78                     break;
79                 }
80             }
81         }
82         addCount(1L, binCount);
83         return null;
84     }
复制代码

 

posted @   堤苏白  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示