1 /**
2 key:键值
3 value:值
4 onlyIfAbsent:true:如果key存在的情况下,不更新值;Flase:如果key存在的情况下,替换old value
5 **/
6 final V putVal(K key, V value, boolean onlyIfAbsent) {
7 //不允许key或value为空
8 if (key == null || value == null) throw new NullPointerException();
9 //在key的hascode值上重新计算key的hash值
10 //【(key.hashCode() ^ (key.hashCode() >>> 16)) & 0x7fffffff;】
11 int hash = spread(key.hashCode());
12 int binCount = 0;
13 //CAS锁
14 for (Node<K,V>[] tab = table;;) {
15 Node<K,V> f; int n, i, fh;
16 /**
17 初始化
18 根据hash确认key的Node位置,当node为空时则CAS尝试写入,写入成功流程结束,否则进行下一次尝试
19 **/
20 if (tab == null || (n = tab.length) == 0)
21 tab = initTable();
22 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
23 if (casTabAt(tab, i, null,
24 new Node<K,V>(hash, key, value, null)))
25 break; // no lock when adding to empty bin
26 }
27 /**
28 static final int MOVED = -1;
29 如果当前位置的 hashcode == MOVED == -1, map 正在扩容,其他线程帮助扩容,也就是多线程扩容。
30 **/
31 else if ((fh = f.hash) == MOVED)
32 tab = helpTransfer(tab, f);
33 else {
34 /**
35 利用 synchronized 锁写入数据
36 fh〉0 说明这个节点是一个链表的节点不是树的节点。
37 如果是红黑树,照树的方式插入值
38 **/
39 V oldVal = null;
40 synchronized (f) {
41 if (tabAt(tab, i) == f) {
42 if (fh >= 0) {
43 binCount = 1;
44 //遍历链表所有结点,如果找到相同key就更新旧值,否则添加至链表尾
45 for (Node<K,V> e = f;; ++binCount) {
46 K ek;
47 if (e.hash == hash &&
48 ((ek = e.key) == key ||
49 (ek != null && key.equals(ek)))) {
50 oldVal = e.val;
51 if (!onlyIfAbsent)
52 e.val = value;
53 break;
54 }
55 Node<K,V> pred = e;
56 if ((e = e.next) == null) {
57 pred.next = new Node<K,V>(hash, key,
58 value, null);
59 break;
60 }
61 }
62 }
63 else if (f instanceof TreeBin) {
64 Node<K,V> p;
65 binCount = 2;
66 if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
67 value)) != null) {
68 oldVal = p.val;
69 if (!onlyIfAbsent)
70 p.val = value;
71 }
72 }
73 }
74 }
75 /**
76 当链表长度大于8时,将链表转换为红黑树
77 **/
78 if (binCount != 0) {
79 if (binCount >= TREEIFY_THRESHOLD)
80 treeifyBin(tab, i);
81 if (oldVal != null)
82 return oldVal;
83 break;
84 }
85 }
86 }
87 //如果是新增元素,将当前ConcurrentHashMap的元素数量+1
88 addCount(1L, binCount);
89 return null;
90 }