zoukankan      html  css  js  c++  java
  • concurrentHashMap源码分析

    ConcurrentHashMap是HashMap的线程安全版本,内部也是使用(数组 + 链表 + 红黑树)的结构来存储元素。

    相比于同样线程安全的HashTable来说,效率等各方面都有极大地提高。,在这里可以使用上篇那个代码进行测试,

    根据结果可以知道ConcurrentHashMap是线程安全的,由于分为16个segemnet所以并发度为16.

    //在插入数据的时候,调用的是下面的方法
    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) {
    //key.value不可以为空
    if (key == null || value == null) throw new NullPointerException();
    //计算hash值
    int hash = spread(key.hashCode());
    //要插入的元素的元素个数
    int binCount = 0;
    //这里for是死循环 (如果cas机制失败了,那么就会重新获取整个桶进行下面的流程)
    for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; if (tab == null || (n = tab.length) == 0)
    //如果桶没有初始化.那么整个桶救赎初始化 tab
    = initTable(); else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
      //cas机制控制安全
    if (casTabAt(tab, i, null,

    // 如果使用CAS插入元素时,发现已经有元素了,则进入下一次循环,重新操作

    // 如果使用CAS插入元素成功,则break跳出循环,流程结束
    new Node<K,V>(hash, key, value, null)))
                        break;                   // no lock when adding to empty bin
                }
                else if ((fh = f.hash) == MOVED)
                    tab = helpTransfer(tab, f);
                else {
                    V oldVal = null;
                    synchronized (f) {
                        if (tabAt(tab, i) == f) {
                            if (fh >= 0) {
                                binCount = 1;
                                for (Node<K,V> e = f;; ++binCount) {
                                    K ek;
                                    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, null);
                                        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;
                                }
                            }
                        }
                    }
                    if (binCount != 0) {
                        if (binCount >= TREEIFY_THRESHOLD)
                            treeifyBin(tab, i);
                        if (oldVal != null)
                            return oldVal;
                        break;
                    }
                }
            }
            addCount(1L, binCount);
            return null;
        }

    整体流程跟HashMap比较类似,大致是以下几步:

    (1)如果桶数组未初始化,则初始化;

    (2)如果待插入的元素所在的桶为空,则尝试把此元素直接插入到桶的第一个位置;

    (3)如果正在扩容,则当前线程一起加入到扩容的过程中;

    (4)如果待插入的元素所在的桶不为空且不在迁移元素,则锁住这个桶(分段锁);

    (5)如果当前桶中元素以链表方式存储,则在链表中寻找该元素或者插入元素;

    (6)如果当前桶中元素以红黑树方式存储,则在红黑树中寻找该元素或者插入元素;

    (7)如果元素存在,则返回旧值;

    (8)如果元素不存在,整个Map的元素个数加1,并检查是否需要扩容;

    添加元素操作中使用的锁主要有(自旋锁 + CAS + synchronized + 分段锁)。

    为什么使用synchronized而不是ReentrantLock?

    因为synchronized已经得到了极大地优化,在特定情况下并不比ReentrantLock差。

  • 相关阅读:
    java基础 01
    c++11——模板的细节改进
    c++11——auto,decltype类型推导
    poj_1182 并查集
    poj_1988 并查集
    poj_1161 并查集
    poj_3067 树状数组
    poj_2182 线段树/树状数组
    poj_1190 树状数组
    动态规划
  • 原文地址:https://www.cnblogs.com/xiufengchen/p/10723186.html
Copyright © 2011-2022 走看看