850.、jdk8中对ConcurrentHashmap的改进

  1. Java 7为实现并⾏访问,引⼊了Segment这⼀结构,实现了分段锁,理论上最⼤并发度与Segment个数相等。
  2. Java 8为进⼀步提⾼并发性,摒弃了分段锁的⽅案,⽽是直接使⽤⼀个⼤的数组。同时为了提⾼哈希碰撞下的寻址性能,Java 8在链表⻓度超过⼀定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红⿊树(寻址时间复杂度为O(long(N)))。
    其数据结构如下图所示
  3. 源码:
    
    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 //ConcurrentHashMap 不允许插⼊null键,HashMap允许插⼊⼀个null键
    8 if (key == null || value == null) throw new NullPointerException();
    9 //计算key的hash值
    10 int hash = spread(key.hashCode());
    11 int binCount = 0;
    12 //for循环的作⽤:因为更新元素是使⽤CAS机制更新,需要不断的失败重试,直到成功为⽌。
    13 for (Node<K,V>[] tab = table;;) {
    14 // f:链表或红⿊⼆叉树头结点,向链表中添加元素时,需要synchronized获取f的锁。
    15 Node<K,V> f; int n, i, fh;
    16 //判断Node[]数组是否初始化,没有则进⾏初始化操作
    17 if (tab == null || (n = tab.length) == 0)
    18 tab = initTable();
    19 //通过hash定位Node[]数组的索引坐标,是否有Node节点,如果没有则使⽤CAS进⾏添加(链表的头结点),添加失败则进⼊下次循环。
    20 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
    21 if (casTabAt(tab, i, null,
    22 new Node<K,V>(hash, key, value, null)))
    23 break; // no lock when adding to empty bin
    24 }
    25 //检查到内部正在移动元素(Node[] 数组扩容)
    26 else if ((fh = f.hash) == MOVED)
    27 //帮助它扩容
    28 tab = helpTransfer(tab, f);
    29 else {
    30 V oldVal = null;
    31 //锁住链表或红⿊⼆叉树的头结点
    32 synchronized (f) {
    33 //判断f是否是链表的头结点
    34 if (tabAt(tab, i) == f) {
    35 //如果fh>=0 是链表节点
    36 if (fh >= 0) {
    37 binCount = 1;
    38 //遍历链表所有节点
    39 for (Node<K,V> e = f;; ++binCount) {
    40 K ek;
    41 //如果节点存在,则更新value
    42 if (e.hash == hash &&
    43 ((ek = e.key) == key ||
    44 (ek != null && key.equals(ek)))) {
    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 //TreeBin是红⿊⼆叉树节点
    60 else if (f instanceof TreeBin) {
    61 Node<K,V> p;
    62 binCount = 2;
    63 //添加树节点
    64 if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
    65 value)) != null) {
    66 oldVal = p.val;
    67 if (!onlyIfAbsent)
    68 p.val = value;
    69 }
    70 }
    71 }
    72 }
    73 
    74 if (binCount != 0) {
    75 //如果链表⻓度已经达到临界值8 就需要把链表转换为树结构
    76 if (binCount >= TREEIFY_THRESHOLD)
    77 treeifyBin(tab, i);
    78 if (oldVal != null)
    79 return oldVal;
    80 break;
    81 }
    82 }
    83 }
    84 //将当前ConcurrentHashMap的size数量+1
    85 addCount(1L, binCount);
    86 return null;
    87 }