如果想更详细了解ConcurrentHashMap 内部工作原来可以去看下我以前写过一篇HashMap源码解析了解下hash 算法原理、数组扩容、红黑树转换等等。
initTable
private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        while ((tab = table) == null || tab.length == 0) {
            if ((sc = sizeCtl) < 0) //这时已经有其他线程获取到执行权,沉睡一会
                Thread.yield(); // lost initialization race; just spin
            else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
                try {
                    if ((tab = table) == null || tab.length == 0) {
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        ("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n]; //初始化数组
                        table = tab = nt;
                        sc = n - (n >>> 2);
                    }
                } finally {
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }这个是初始化map数组,核心是sizeCtl 这个变量:一个使用volatile修饰共享变量,作用通过交换比较竞争获取初始化或者扩容数组执行权。当线程发现sizeCtl小于0的时候,线程就会让出执行权,当线程成功竞争设置-1 就相当于获取到执行权,所以就可以去初始化数组了。当为正数时,保存下一个要调整Map大小的元素计数值
说明下Unsafe 交换比较方法
/**
     * 通过对象属性的值,修改前、更新后一致,才是更新成功
     * @param o 需要被修改的属性的对象
     * @param l 对象Field的指针地址,可以理解成属性值引用
     * @param i 修改前的值
     * @param i1 修改后的值
     * @return
     */
    public final native boolean compareAndSwapInt(java.lang.Object o, long l, int i, int i1);put方法解析
public V put(K key, V value) {
        return putVal(key, value, false);
    }
    final V putVal(K key, V value, boolean onlyIfAbsent) {
       //ConcurrentHashMap 不允许key value为空,因为在并发情况下不能通过获取get(key) 判断key存不存在
        if (key == null || value == null) throw new NullPointerException(); 
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh; K fk; V fv;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { //通过计算hash得到数组下标,为空通过交换比较设置进去,这时不需要加锁的
                if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
                    break;                   // no lock when adding to empty bin
            }
            else if ((fh = f.hash) == MOVED)  //这种情况说明数组正在扩容,需要对链表和黑红树进行迁移
                tab = helpTransfer(tab, f);
            else if (onlyIfAbsent // check first node without acquiring lock
                     && fh == hash
                     && ((fk = f.key) == key || (fk != null && key.equals(fk)))
                     && (fv = f.val) != null)
                return fv;









