|
| 1 | +package concurrenthashmap; |
| 2 | + |
| 3 | +import java.util.concurrent.ConcurrentHashMap; |
| 4 | + |
| 5 | +/** |
| 6 | + * jdk1.8后,结构和1.8后的hashmap类似 |
| 7 | + * <p> |
| 8 | + * 1.7是16个Segment,每个Segment里面是类似hashmap的结构 |
| 9 | + * 1.8是链表+红黑树 |
| 10 | + * <p> |
| 11 | + * ConcurrentHashMap源码浅析 |
| 12 | + * |
| 13 | + * @Author: zzStar |
| 14 | + * @Date: 10-11-2020 20:22 |
| 15 | + */ |
| 16 | +public class ConcurrentHashMapAnalysis { |
| 17 | +} |
| 18 | + |
| 19 | +/* |
| 20 | + public V get(Object key) { |
| 21 | + ConcurrentHashMap.Node<K,V>[] tab; ConcurrentHashMap.Node<K,V> e, p; int n, eh; K ek; |
| 22 | + //得到hash值 |
| 23 | + int h = spread(key.hashCode()); |
| 24 | + if ((tab = table) != null && (n = tab.length) > 0 && |
| 25 | + (e = tabAt(tab, (n - 1) & h)) != null) { |
| 26 | + if ((eh = e.hash) == h) { |
| 27 | + //槽点和key符合则直接返回value |
| 28 | + if ((ek = e.key) == key || (ek != null && key.equals(ek))) |
| 29 | + return e.val; |
| 30 | + } |
| 31 | + //负数说明,得到的是一个红黑树结点或者为转移结点,调用find方法取值 |
| 32 | + else if (eh < 0) |
| 33 | + return (p = e.find(h, key)) != null ? p.val : null; |
| 34 | + //若均不是,则遍历链表取值 |
| 35 | + while ((e = e.next) != null) { |
| 36 | + if (e.hash == h && |
| 37 | + ((ek = e.key) == key || (ek != null && key.equals(ek)))) |
| 38 | + return e.val; |
| 39 | + } |
| 40 | + } |
| 41 | + return null; |
| 42 | + } |
| 43 | +*/ |
| 44 | + |
| 45 | + |
| 46 | +/* |
| 47 | + final V putVal(K key, V value, boolean onlyIfAbsent) { |
| 48 | + //判断是否为空,不允许为空 |
| 49 | + if (key == null || value == null) throw new NullPointerException(); |
| 50 | + //计算hash值 |
| 51 | + int hash = spread(key.hashCode()); |
| 52 | + int binCount = 0; |
| 53 | + //根据对应位置节点的类型来赋值,或者helpTransfer,或者增长链表,或者给红黑树增加节点 |
| 54 | + for (ConcurrentHashMap.Node<K,V>[] tab = table;;) { |
| 55 | + ConcurrentHashMap.Node<K,V> f; int n, i, fh; K fk; V fv; |
| 56 | + if (tab == null || (n = tab.length) == 0) |
| 57 | + //初始化tab |
| 58 | + tab = initTable(); |
| 59 | + else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { |
| 60 | + //cas操作,直接放进去 |
| 61 | + if (casTabAt(tab, i, null, new ConcurrentHashMap.Node<K,V>(hash, key, value))) |
| 62 | + break; // no lock when adding to empty bin |
| 63 | + } |
| 64 | + //MOVED转移结点,说明槽点正在扩容,帮助进行 |
| 65 | + else if ((fh = f.hash) == MOVED) |
| 66 | + tab = helpTransfer(tab, f); |
| 67 | + else if (onlyIfAbsent // check first node without acquiring lock |
| 68 | + && fh == hash |
| 69 | + && ((fk = f.key) == key || (fk != null && key.equals(fk))) |
| 70 | + && (fv = f.val) != null) |
| 71 | + return fv; |
| 72 | + else { |
| 73 | + V oldVal = null; |
| 74 | + synchronized (f) { |
| 75 | + if (tabAt(tab, i) == f) { |
| 76 | + if (fh >= 0) { |
| 77 | + binCount = 1; |
| 78 | + for (ConcurrentHashMap.Node<K,V> e = f;; ++binCount) { |
| 79 | + K ek; |
| 80 | + //判断当前是否存在这个key |
| 81 | + if (e.hash == hash && |
| 82 | + ((ek = e.key) == key || |
| 83 | + (ek != null && key.equals(ek)))) { |
| 84 | + oldVal = e.val; |
| 85 | + if (!onlyIfAbsent) |
| 86 | + e.val = value; |
| 87 | + break; |
| 88 | + } |
| 89 | + //不存在就新创建一个结点 |
| 90 | + ConcurrentHashMap.Node<K,V> pred = e; |
| 91 | + if ((e = e.next) == null) { |
| 92 | + pred.next = new ConcurrentHashMap.Node<K,V>(hash, key, value); |
| 93 | + break; |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + //红黑树 |
| 98 | + else if (f instanceof ConcurrentHashMap.TreeBin) { |
| 99 | + ConcurrentHashMap.Node<K,V> p; |
| 100 | + binCount = 2; |
| 101 | + if ((p = ((ConcurrentHashMap.TreeBin<K,V>)f).putTreeVal(hash, key, |
| 102 | + value)) != null) { |
| 103 | + oldVal = p.val; |
| 104 | + if (!onlyIfAbsent) |
| 105 | + p.val = value; |
| 106 | + } |
| 107 | + } |
| 108 | + else if (f instanceof ConcurrentHashMap.ReservationNode) |
| 109 | + throw new IllegalStateException("Recursive update"); |
| 110 | + } |
| 111 | + } |
| 112 | + //完成添加后,判断是否需要将链表转为树 |
| 113 | + if (binCount != 0) { |
| 114 | + //大于阈值8,则转为树 |
| 115 | + if (binCount >= TREEIFY_THRESHOLD) |
| 116 | + //treeifyBin还要满足最低容量条件64 |
| 117 | + treeifyBin(tab, i); |
| 118 | + if (oldVal != null) |
| 119 | + return oldVal; |
| 120 | + break; |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + addCount(1L, binCount); |
| 125 | + return null; |
| 126 | + } |
| 127 | +*/ |
| 128 | + |
| 129 | +/** |
| 130 | + * 为什么超过8要转为红黑树? |
| 131 | + * 1.默认是链表,红黑树每个节点占用的空间是链表的2倍 |
| 132 | + * 2.经过泊松分布,hash冲突到达8的时候概率小于千万分之1 (0.00000006),正常情况下,链表的长度不会达到8,但为保证极端情况下,仍有较高的查询效率,转为红黑树 |
| 133 | + */ |
0 commit comments