ConcurrentHashMap源码分析(一) ---- 插入,扩容,计算总数据量

基于jdk8(存在bug,jdk12修复了)贴下地址,https://bugs.openjdk.java.net/browse/JDK-8214427。
先看到部分成员变量和常量

	
	//map中最大的容量
    private static final int MAXIMUM_CAPACITY = 1 << 30;
    //默认的容量
	private static final int DEFAULT_CAPACITY = 16;
	//默认的扩容因子
	private static final float LOAD_FACTOR = 0.75f;
	//节点从链表升级为红黑树的阈值
	static final int TREEIFY_THRESHOLD = 8;
	//节点从红黑树降级为链表的阈值
	static final int UNTREEIFY_THRESHOLD = 6;
	//table的大小小于该值时,节点链表数量大于等于8也不会升级为红黑树,而是选择扩容
	static final int MIN_TREEIFY_CAPACITY = 64;

	//table被迁移完成的节点的hash值
    static final int MOVED     = -1; // hash for forwarding nodes
    //table的节点为红黑树节点的hash值
    static final int TREEBIN   = -2; // hash for roots of trees
    //int 32 位 , 第一位为0 ,其余位为1 , int 的最大值。
    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
  	
  	//数组
  	transient volatile Node<K,V>[] table;
	//扩容时的新数组
	private transient volatile Node<K,V>[] nextTable;
	
	//这两个值一起合计为总数据量
	private transient volatile long baseCount;
	private transient volatile CounterCell[] counterCells;
	//表示 counterCells 是否能进行这些操作 ( counterCells初始化 或 counterCells某个位置的初始值设置 或 扩容操作 )
	private transient volatile int cellsBusy;
	
	//扩容阈值 ,也可以是负数 , 表示正在扩容或者初始化
	private transient volatile int sizeCtl;
	//表示map扩容时,还没有被迁移的数组位置的下标 + 1 ,迁移是从数组后面往前迁移。
	private transient volatile int transferIndex;

直接看到最关键的put方法

    public V put(K key, V value) {
        return putVal(key, value, false);
    }
	final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        //计算hash值
        int hash = spread(key.hashCode());
        int binCount = 0;
        //tab被赋值为table,  死循环
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            //table还未初始化
            if (tab == null || (n = tab.length) == 0)
            	//初始化table
                tab = initTable();
            //计算出位置,获取table上该位置的值为f , 判断f是否为空 。
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                //该位置上没有值,则cas设置值
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    //设置成功跳出死循环
                    break;                   // no lock when adding to empty bin
            }
            //如果f的hash值是MOVED , 表示该位置上的节点被迁移到新的table了(正在扩容)
            else if ((fh = f.hash) == MOVED)
            	//尝试参与到迁移工作
                tab = helpTransfer(tab, f);
            //f不为空,且hash值不是MOVED,则加入到f的链表或者红黑树中
            else {
                V oldVal = null;
                //锁住f
                synchronized (f) {
                	//防止被其他线程修改了,再次判断是否为f
                    if (tabAt(tab, i) == f) {
                    	//f的hash值大于0,不是红黑树
                        if (fh >= 0) {
                        	//binCount 赋值为1
                            binCount = 1;
                            //循环遍历f链表,binCount累加
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
                                //判断插入的key是否已经存在
                                if (e.hash == hash &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    //获取旧值
                                    oldVal = e.val;
                                    //如果onlyIfAbsent为false
                                    if (!onlyIfAbsent)
                                    	//替换原本的值为插入进来的新值
                                        e.val = value;
                                    break;
                                }
                                Node<K,V> pred = e;
                                //如果下一个节点为空,则到了链表尾部
                                if ((e = e.next) == null) {
                                	//插入的数据包装为新的node,使用尾部的节点指向新的node
                                    pred.next = new Node<K,V>(hash, key,
                                                              value, null);
                                    //跳出循环
                                    break;
                                }
                            }
                        }
                        //如果是树节点
                        else if (f instanceof TreeBin) {
                            Node<K,V> p;
                            //binCount 赋值为2
                            binCount = 2;
                            //插入到树中
                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                           value)) != null) {
                                oldVal = p.val;
                                if (!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                    }
                }
                if (binCount != 0) {
                	//如果binCount 大于树化的阈值
                    if (binCount >= TREEIFY_THRESHOLD)
                    	//升级为红黑树,如果table长度小于MIN_TREEIFY_CAPACITY ,不会升级为红黑树,而是触发扩容
                        treeifyBin(tab, i);
                    if (oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
        //看到这个方法 , 扩容检查,扩容, 调整baseCount和counterCells来记录总数据量
        addCount(1L, binCount);
        return null;
    }

	//& HASH_BITS 为了确保结果一定为正数 。 迁移中的节点和树的节点的hash值为负数,以便区分。
	static final int spread(int h) {
        return (h ^ (h >>> 16)) & HASH_BITS;
    }

initTable方法

	private final Node<K,V>[] initTable() {
        Node<K,V>[] tab; int sc;
        //table未初始化,一直循环,只允许一个线程初始化table
        while ((tab = table) == null || tab.length == 0) {
        	//table正在被其他线程初始化,让出cpu资源
            if ((sc = sizeCtl) < 0)
                Thread.yield(); // lost initialization race; just spin
            //cas将sizeCtl修改为-1
            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                	//防止被其他线程初始化了,再次判断
                    if ((tab = table) == null || tab.length == 0) {
                    	//如果调用构造函数的时候指定了容量,使用指定的,否则使用默认容量
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        //实例化table
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = tab = nt;
                        //0.75倍的n , 扩容阈值
                        sc = n - (n >>> 2);
                    }
                } finally {
                	//设置sizeCtl 为扩容阈值
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }

addCount方法

	private final void addCount(long x, int check) {
        CounterCell[] as; long b, s;
        //counterCells不为空 或者 cas修改baseCount失败
        if ((as = counterCells) != null ||
            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
            CounterCell a; long v; int m;
            boolean uncontended = true;
            //如果counterCells没被初始化
            if (as == null || (m = as.length - 1) < 0 ||
            	//走到这里说明counterCells被初始化过了
            	//ThreadLocalRandom.getProbe()获得当前线程的Probe值 
            	//& (counterCells 长度 -1),来获取到counterCells中的一个位置的值
                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
                //走到这里,说明counterCells该位置的值不为空
                //则当前线程cas设置counterCell的value值 加上 x 
                !(uncontended =
                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
                //cas失败,调用fullAddCount方法,直至增加counterCell或者baseCount成功
                fullAddCount(x, uncontended);
                return;
            }  
            //删除元素 ,check 为-1 ,不用进行扩容进程,直接return
            if (check <= 1)
                return;
            //统计map中所有的数据量赋值给s
            s = sumCount();
        }
        //可能需要扩容
        if (check >= 0) {
            Node<K,V>[] tab, nt; int n, sc;
            //由于扩容和插入是一起进行的,可能扩容后还会接着扩容,所以是一个while循环
            //如果超过了扩容阈值 且 没达到tab的最大限制, 进行扩容操作
            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
                   (n = tab.length) < MAXIMUM_CAPACITY) {
                //使用当前table的长度获得一个值(该值第16位为1),这里我们把它叫做扩容戳(由于从左到右的0的个数少了一个(2的次方倍的扩容)所以下一次生成的扩容戳会比之前的扩容戳小1)
                int rs = resizeStamp(n);
                //如果sizeCtl小于0,说明有线程在对table扩容
                if (sc < 0) {
                	//如果是同一个n生成的扩容戳,(sc >>> RESIZE_STAMP_SHIFT,右移16位抛弃掉帮助扩容的+1和初始扩容的+2) 会等于rs
                	
                	//sc == rs + 1 这个条件永远不会成立 这是bug
                	//sc == rs + MAX_RESIZERS 这个条件永远不会成立 这是bug
               		//这里应该是sc == rs << RESIZE_STAMP_SHIFT + 1  (最后一个线程完成了迁移工作,最开始是+2,完成迁移工作以后-1,则为+1)
               		//这里应该是sc == rs << RESIZE_STAMP_SHIFT + MAX_RESIZERS (只用了后16位来对迁移的线程数进行累加,超过了该值,怎不能再帮忙迁移)
                	
                	//nextTable为空 (扩容完成则nextTable被设置为控)
                	//transferIndex小于等于0 则table没有可以帮助扩容的位置了,被其他线程先抢到去扩容了。大于0,则可以帮助扩容
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                        transferIndex <= 0)
                        //上述任一条件为真都直接跳出循环
                        break;
                    //cas给SIZECTL + 1 ,表示多了一个线程来帮助扩容了
                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                    	//扩容
                        transfer(tab, nt);
                }
                //还没有线程对table进行扩容
                //cas修改sizeCtl为(rs << RESIZE_STAMP_SHIFT) + 2) ,对扩容戳左移16位(由于第16位为1)此时sizeCtl为负数,然后加2
                else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    //扩容
                    transfer(tab, null);
                //重新获取数据量
                s = sumCount();
            }
        }
    }
	
	//单独占用一个缓存行,避免伪共享,使得counterCells各个值的操作互不干扰
	@sun.misc.Contended static final class CounterCell {
		//只有一个value用来计数
	    volatile long value;
	    CounterCell(long x) { value = x; }
	}

ThreadLocalRandom的部分方法

    static final int getProbe() {
    	//获取Thread类的threadLocalRandomProbe字段值 , 该字段也被@sun.misc.Contended修饰
        return UNSAFE.getInt(Thread.currentThread(), PROBE);
    }
    private static final int PROBE_INCREMENT = 0x9e3779b9;
    static final void localInit() {
        //获取PROBE_INCREMENT 的值
        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
        int probe = (p == 0) ? 1 : p; // skip 0
        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
        //获取当前线程
        Thread t = Thread.currentThread();
        UNSAFE.putLong(t, SEED, seed);
        //设置threadLocalRandomProbe的值为p 
        UNSAFE.putInt(t, PROBE, probe);
    }
    //重置一个新PROBE的值
    static final int advanceProbe(int probe) {
        probe ^= probe << 13;   // xorshift
        probe ^= probe >>> 17;
        probe ^= probe << 5;
        UNSAFE.putInt(Thread.currentThread(), PROBE, probe);
        return probe;
    }

sumCount方法

	final long sumCount() {
		//累加所有counterCells的值,和 baseCount
        CounterCell[] as = counterCells; CounterCell a;
        long sum = baseCount;
        if (as != null) {
            for (int i = 0; i < as.length; ++i) {
                if ((a = as[i]) != null)
                    sum += a.value;
            }
        }
        return sum;
    }

fullAddCount方法

	private final void fullAddCount(long x, boolean wasUncontended) {
        int h;
        //如果Probe为0
        if ((h = ThreadLocalRandom.getProbe()) == 0) {
        	//初始化Probe
            ThreadLocalRandom.localInit();      // force initialization
            //获取Probe赋值给h,用来定位到CounterCell数组具体位置
            h = ThreadLocalRandom.getProbe();
            wasUncontended = true;
        }
        boolean collide = false;                // True if last slot nonempty
        //死循环
        for (;;) {
            CounterCell[] as; CounterCell a; int n; long v;
            //如果counterCells已经初始化
            if ((as = counterCells) != null && (n = as.length) > 0) {
            	//h & 长度减1 , 获取到counterCells指定位置的counterCell赋值给a
            	//如果该位置的值为空
                if ((a = as[(n - 1) & h]) == null) {
                	//如果没有在进行扩容操作或者对某个位置进行初始赋值
                    if (cellsBusy == 0) {            // Try to attach new Cell
                    	//用x实例化一个CounterCell 为 r
                        CounterCell r = new CounterCell(x); // Optimistic create
                        //如果没有在进行扩容操作或者对某个位置进行初始赋值 , cas 将 cellsBusy修改为 1
                        if (cellsBusy == 0 &&
                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                            boolean created = false;
                            try {               // Recheck under lock
                                CounterCell[] rs; int m, j;
                                //再次判断counterCells该位置是否可以进行初始赋值
                                if ((rs = counterCells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    //将该位置的值改为 r 
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                            	//将cellsBusy 修改回 0 
                                cellsBusy = 0;
                            }
                            if (created)
                            	//跳出死循环
                                break;
                           //该位置的数据被其他线程先初始赋值了,接着循环
                            continue;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                }
                //如果wasUncontended为false , 修改为 true
                else if (!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                //cas对counterCells对应的位置上counterCell的value值增加x ,成功则跳出循环
                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                    break;
                //counterCells 被其他线程修改 或者 counterCells 长度大于等于核心数 ,修改collide 为 false
                else if (counterCells != as || n >= NCPU)
                    collide = false;            // At max size or stale
                //collide 为false ,修改collide为true
                else if (!collide)
                    collide = true;
                //collide 为 true 且 竞争修改 counterCells  和 baseCount 失败才会走到这里 , 说明竞争很激烈了已经,对counterCells进行扩容操作 , 以便支持更多线程同时操作
                //如果cellsBusy 为0, cas 修改 CELLSBUSY为1
                else if (cellsBusy == 0 &&
                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                    try {
                    	//再次判断counterCells 没有被其他线程修改
                        if (counterCells == as) {// Expand table unless stale
                        	//扩容两倍
                            CounterCell[] rs = new CounterCell[n << 1];
                            //拷贝原CounterCells的值到新的CounterCells
                            for (int i = 0; i < n; ++i)
                                rs[i] = as[i];
                            //将counterCells 设置为 新的 CounterCells 
                            counterCells = rs;
                        }
                    } finally {
                    	//cellsBusy 修改回 0 
                        cellsBusy = 0;
                    }
                   	//collide 修改回false
                    collide = false;
                    //进行下次循环
                    continue;                   // Retry with expanded table
                }
                //将Probe重置为其他值,很可能下次循环操作counterCells其他位置
                h = ThreadLocalRandom.advanceProbe(h);
            }
            //如果cellsBusy  == 0 (可以进行初始化)
            //counterCells == as , counterCells还没有被其他线程修改
            //cas设置cellsBusy  为 1 
            else if (cellsBusy == 0 && counterCells == as &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                boolean init = false;
                try {                           // Initialize table
                	//再次判断counterCells 未被其他线程修改过
                    if (counterCells == as) {	
                    	//实例化一个CounterCell,长度为2
                        CounterCell[] rs = new CounterCell[2];
                        //使用h & 1 , 定位到可以操作的位置, 设置为x
                        rs[h & 1] = new CounterCell(x);
                        //将counterCells 修改为rs ,此时counterCells 初始化完成
                        counterCells = rs;
                        init = true;
                    }
                } finally {
                	//修改回0
                    cellsBusy = 0;
                }
                if (init)
                	//跳出死循环
                    break;
            }
            //被其他线程去初始化了, cas 尝试将baseCount增加x , 成功则跳出死循环
            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
                break;                          // Fall back on using base
        }
    }

transfer方法

	private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
		//n为原数组的长度
        int n = tab.length, stride;
        //每个线程最少要迁移table的MIN_TRANSFER_STRIDE (16) 个位置的数据
        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
            stride = MIN_TRANSFER_STRIDE; // subdivide range
        //新的数组为空
        if (nextTab == null) {            // initiating
            try {
            	//初始化两倍的数组
                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
                //nextTab 赋值为 新数组
                nextTab = nt;
            } catch (Throwable ex) {      // try to cope with OOME
                sizeCtl = Integer.MAX_VALUE;
                return;
            }
            //nextTable 赋值为 新数组
            nextTable = nextTab;
            //transferIndex 初始设置为 原数组的长度
            transferIndex = n;
        }
        //获取新数组的长度
        int nextn = nextTab.length;
        //实例化一个hash值为MOVED的节点 , key value为空
        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
        boolean advance = true;
        //迁移工作是否全部完成
        boolean finishing = false; // to ensure sweep before committing nextTab
        //i bound 初始为 0 
        for (int i = 0, bound = 0;;) {
            Node<K,V> f; int fh;
            while (advance) {
                int nextIndex, nextBound;
                //--i 接着迁移前面一个节点
                //--i >= bound 则当前线程还有节点没有迁移完 或者 finishing为true
                // 则 advance 修改为false,跳出while循环
                if (--i >= bound || finishing)
                    advance = false;
                //nextIndex 赋值为 transferIndex ,transferIndex小于等于0 ,则说明table所有的位置都有线程在迁移了
                else if ((nextIndex = transferIndex) <= 0) {
                	//修改i 为 -1 ,小于0了
                    i = -1;
                    advance = false;
                }
                //如果table还有可以迁移位置
                //cas 修改 transferIndex 为 nextBound ,被减去的stride 为当前线程要迁移的table的位置的个数
                //当nextBound 被减到0 ,则全部位置都有线程在迁移了
                //transferIndex 初始设置为 原数组的长度, 显然table后面的位置先开始迁移
                else if (U.compareAndSwapInt
                         (this, TRANSFERINDEX, nextIndex,
                          nextBound = (nextIndex > stride ?
                                       nextIndex - stride : 0))) {
                    //剩余要迁移的数量赋值给bound 
                    bound = nextBound;
                    //表示该线程开始迁移的table的初始位置
                    i = nextIndex - 1;
                    //advance 修改为 false,跳出while循环
                    advance = false;
                }
            }
            //如果i < 0 , 说明当前线程迁移工作做完了
            if (i < 0 || i >= n || i + n >= nextn) {
                int sc;
                //如果finishing为true
                if (finishing) {
                	//将nextTable设置为空
                    nextTable = null;
                    //将table修改为新的Table
                    table = nextTab;
                    //扩容阈值为新的table长度的0.75
                    sizeCtl = (n << 1) - (n >>> 1);
                    //返回
                    return;
                }
                //先将sizeCtl赋值给sc
                //cas将sizeCtl 减一 , 表示有一个线程已经做完了迁移工作
                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
                	//此时sc还是扣减一之前的值
                	//sizeCtl 已经被扣减一了,导致比扩容戳少了一 , 所以sc保存减一之前的值
                	//如果sc的值减2 和扩容戳 左移 16 位不等, 则说明还有线程在做迁移工作
                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                    	//还有其他线程在迁移,当前线程迁移工作做完了,则直接return出去
                        return;
                    //走到这里说明当前线程为最后一个做完迁移工作的线程
                    //finishing   advance  修改位 true
                    finishing = advance = true;
                    //将i 设置回 原table的长度
                    i = n; // recheck before commit
                }
            }
            //获取该位置上的数据为f
            //如果该位置为空,则该位置不用迁移,cas将该位置的节点设置为fwd,标识该位置已经迁移到新的table了
            else if ((f = tabAt(tab, i)) == null)
                advance = casTabAt(tab, i, null, fwd);
            //获取该位置上的数据的hash为fh
            //如果该值已经被迁移了,修改advance 为true
            else if ((fh = f.hash) == MOVED)
                advance = true; // already processed
            //正常迁移原table节点上的数据
            else {
                synchronized (f) {
                	//再次判断该位置上的数据为f
                    if (tabAt(tab, i) == f) {
                        Node<K,V> ln, hn;
                        //迁移链表 ,  这里和HashMap的迁移不一样,
                        if (fh >= 0) {
                        	//fh & 原table长度 计算出runBit ,1或者0
                            int runBit = fh & n;
                            //lastRun 保存原链表的尾节点
                            Node<K,V> lastRun = f;
                            //遍历原链表
                            //获取下一个节点为p
                            for (Node<K,V> p = f.next; p != null; p = p.next) {
                            	//& 原table长度,table长度为2的幂次方,原hash对应高一位的值用来区分开原节点
                                int b = p.hash & n;
                                //b的结果和runBit不等
                                if (b != runBit) {
                                	//runBit 修改为 b 
                                    runBit = b;
                                    //修改lastRun 为  p
                                    lastRun = p;
                                }
                            }
                            //设置0 链表 的 头结点为 lastRun
                            if (runBit == 0) {
                                ln = lastRun;
                                hn = null;
                            }
                            //设置1 链表 的 头节点为 lastRun
                            else {
                                hn = lastRun;
                                ln = null;
                            }
                            //遍历原链表 ,直至下一个节点不为 lastRun 
                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
                                int ph = p.hash; K pk = p.key; V pv = p.val;
                                //实例化node节点,next属性为ln
                                //然后将ln修改为自己     (和原链表的顺序反了,lastRun节点顺序没反)
                                if ((ph & n) == 0)
                                    ln = new Node<K,V>(ph, pk, pv, ln);
                                //实例化node节点,next属性为hn
                                //然后将hn修改为自己    (和原链表的顺序反了,lastRun节点顺序没反)
                                else
                                    hn = new Node<K,V>(ph, pk, pv, hn);
                            }
                            //将0 链表设置到 新table的i位置上
                            setTabAt(nextTab, i, ln);
                            //将1 链表设置到 新table的i+n位置上
                            setTabAt(nextTab, i + n, hn);
                            //将原table的i位置设置为fwd
                            setTabAt(tab, i, fwd);
                            //修改advance为true 
                            advance = true;
                        }
                        //迁移红黑树
                        else if (f instanceof TreeBin) {
                            TreeBin<K,V> t = (TreeBin<K,V>)f;
                            //一样的,按照 & 运算结果的 1 0 区分开原本的节点
                            TreeNode<K,V> lo = null, loTail = null;
                            TreeNode<K,V> hi = null, hiTail = null;
                            //用来计数,是否需要降级为链表,或者接着构造新的红黑树
                            int lc = 0, hc = 0;
                            //遍历红黑树
                            for (Node<K,V> e = t.first; e != null; e = e.next) {
                                int h = e.hash;
                                //实例化一个TreeNodo为 p 
                                TreeNode<K,V> p = new TreeNode<K,V>
                                    (h, e.key, e.val, null, null);
                                if ((h & n) == 0) {
                                	//将lo头结点设置为p
                                    if ((p.prev = loTail) == null)
                                        lo = p;
                                    //将尾节点的next属性为p
                                    else
                                        loTail.next = p;
                                    //lo尾节点设置为p
                                    loTail = p;
                                    ++lc;
                                }
                                else {
                                    //将hi头结点设置为p
                                    if ((p.prev = hiTail) == null)
                                        hi = p;
                                    //将尾节点的next属性为p  
                                    else
                                        hiTail.next = p;
                                    //hi尾节点设置为p    
                                    hiTail = p;
                                    ++hc;
                                }
                            }
                            //数量小于等于6时,降级为链表,否则构造红黑树
                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                                (hc != 0) ? new TreeBin<K,V>(lo) : t;
                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                                (lc != 0) ? new TreeBin<K,V>(hi) : t;
                            //将头结点设置到新的table
                            setTabAt(nextTab, i, ln);
                            setTabAt(nextTab, i + n, hn);
                            //将原table的节点设置为fwd
                            setTabAt(tab, i, fwd);
                            //修改advance为true 
                            advance = true;
                        }
                    }
                }
            }
        }
    }

helpTransfer方法

	final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
        Node<K,V>[] nextTab; int sc;
        //nextTable不为空,则迁移工作还没完全做完
        if (tab != null && (f instanceof ForwardingNode) &&
            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
            //原table长度获取扩容戳
            int rs = resizeStamp(tab.length);
            //nextTable 和  table 还没被改变 , sizeCtl小于0, 说明还没迁移完毕
            while (nextTab == nextTable && table == tab &&
                   (sc = sizeCtl) < 0) {
                //迁移戳不等
                
                //sc == rs + 1 这个条件永远不会成立 这是bug  (jdk12修复了) 
                //sc == rs + MAX_RESIZERS 这个条件永远不会成立 这是bug (jdk12修复了)
               	//这里应该是sc == rs << RESIZE_STAMP_SHIFT + 1  (最后一个线程完成了迁移工作,最开始是+2,完成迁移工作以后-1,则为+1)
               	//这里应该是sc == rs << RESIZE_STAMP_SHIFT + MAX_RESIZERS (只用了后16位来对迁移的线程数进行累加,超过了该值,怎不能再帮忙迁移)
               	
                //所有节点都有线程在迁移
                //则直接跳出
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || transferIndex <= 0)
                    break;
                //可以帮忙进行迁移
                //cas将 sizeCtl 加一 
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
                	//迁移去
                    transfer(tab, nextTab);
                    break;
                }
            }
            return nextTab;
        }
        return table;
    }

篇幅有限,下篇文章再来看获取和删除操作的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值