ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java集合005 --- ConcurrentHashMap

2020-05-26 22:55:01  阅读:324  来源: 互联网

标签:key Node ConcurrentHashMap hash 005 binCount tab Java null


前言

ConcurrentHashMap内部实现和HashMap类似,都采用了数组+单链表+红黑树的结构;区别是:ConcurrentHashMap是线程安全的;

ConcurrentHashMap线程安全在JDK1.7中由ReentLock和分段锁保证,在JDK1.8版本做了优化,使用synchronized+CAS+分段锁保证

为啥1.8要是用synchronized呢? 在印象中,synchronized不是效率很低么?synchronized其实也是可重入的,并且在近几个版本做了优化

这里不过多的写ConcurrentHashMap原理,这里只是说明下ConcurrentHashMap中使用的自旋锁和分段锁思想

直接上ConcurrentHashMap的put方法:

final V putVal(K key, V value, boolean onlyIfAbsent) {
    if (key == null || value == null) throw new NullPointerException();
    // 计算hash, 和HashMap类似
    int hash = spread(key.hashCode());
    int binCount = 0;
    // 循环, 注意这里没有结束条件, 是依靠其中的流程退出循环; 这是为了在CAS时, 使用自旋锁思想
    for (Node<K,V>[] tab = table;;) {
        Node<K,V> f; int n, i, fh;
        // 数组为空, 初始化数组
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        // 未命中, CAS添加元素; 添加失败, 重新开启循环
        // 这里添加失败的原因可能是并发场景下,其他线程修改了取值
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            if (casTabAt(tab, i, null,
                         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 {
            // 命中后需要加锁, 将元素merge到树或者链表,或者数组
            V oldVal = null;
            // 注意这里的锁对象f是指定索引数组元素, 这就是分段锁
            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;
}

这块就写这么多吧,写不下去了。。。。。

标签:key,Node,ConcurrentHashMap,hash,005,binCount,tab,Java,null
来源: https://www.cnblogs.com/sniffs/p/12969291.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有