zoukankan      html  css  js  c++  java
  • ConcurrentHashMap

    ConcurrentHashMap探究

    • ConcurrentHashMap的key和value不能为空
    Node
        static class Node<K,V> implements Map.Entry<K,V> {
            final int hash;
            final K key;
            volatile V val;
            volatile Node<K,V> next;
        }
    
    put操作

    hash操作

        // (h = key.hashCode()) ^ (h >>> 16)
    	static final int spread(int h) {
            //比HashMap多并上了一个HASH_BITS
            //HASH_BITS
            //static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
            //HASH_BITS是0x7fffffff,该步是为了消除最高位上的负符号 hash的负在ConcurrentHashMap中有特殊意义表示在扩容或者是树节点
            return (h ^ (h >>> 16)) & HASH_BITS;  
        }
    
    public V put(K key, V value) {
        return putVal(key, value, false);
    }
    
      //casTabAt主要用于CAS比较该索引处是否为null防止其它线程已改变该值,null则插入,break结束死循环  
    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                            Node<K,V> c, Node<K,V> v) {
            return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
        }
    
        //获取数组i索引的Node CAS操作 保持其它线程对table的改变在这里可见
    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
            return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
        }
    
    
    
        /** 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 (Node<K,V>[] tab = table;;) {
                Node<K,V> f; int n, i, fh;
                //table为null或空map时进行初始化
                if (tab == null || (n = tab.length) == 0)
                    tab = initTable();
                // 判断当前索引位置的数组上是否有值  无值那就是首元素插入
                //获取数组i索引的Node CAS操作 保持其它线程对table的改变在这里可见
                else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                    //casTabAt主要用于CAS比较该索引处是否为null防止其它线程已改变该值,null则插入,break结束死循环
                    if (casTabAt(tab, i, null,
                                 new Node<K,V>(hash, key, value, null)))
                        break;                   // no lock when adding to empty bin
                }
                //首地址处不null 并且Node的hash是-1  表示是ForwardingNode节点正在rehash扩容
                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;
                    }
                }
            }
            // 更新baseCount
            addCount(1L, binCount);
            return null;
        }
    
  • 相关阅读:
    手把手带你画一个 时尚仪表盘 Android 自定义View
    新手自定义view练习实例之(二) 波浪view
    新手自定义view练习实例之(一) 泡泡弹窗
    增加辅助的数据库组件
    解决Plugin is too old,please update to a more recent version,or set ANDROID_DAILY_OVERRIDE..
    Android 自定义View -- 简约的折线图
    android 开源图表库MPChart最简单使用方法示例教程Demo--折线图 柱状图
    改善database schema
    题解报告:hdu 2057 A + B Again
    hdu 2087 剪花布条(KMP入门)
  • 原文地址:https://www.cnblogs.com/renqiqiang/p/9451301.html
Copyright © 2011-2022 走看看