ConcurrentHashMap源码分析

public V put(K key, V value) {
 return putVal(key, value, false);
}
public V putIfAbsent(K key, V value) {
    return putVal(key, value, true);
}

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
    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;
        //懒初始化:如果数组为null,初始化。数组长度16,扩容因子默认0.75
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        //如果数组该位置为null,那么赋值
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
        	//基于CAS实现,保证并发安全性
        	//只会有一个线程发现该为null,后续的线程则会得到new Node<K, V>
            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 {
            V oldVal = null;
            //对该节点加锁
            synchronized (f) {
            	//再次确认一下
                if (tabAt(tab, i) == f) {
                	//fh>=0,说明是链表
                    if (fh >= 0) {
                        binCount = 1;	//记录链表的长度
                        for (Node<K,V> e = f;; ++binCount) {
                            K ek;
                            //如果发现了一个相同的(k, v)
                            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) {
            	//链表长度 >= TREEIFY_THRESHOLD
            	//tab.length < 64,扩容;> 64,转换成红黑树
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    addCount(1L, binCount);	//下文将详细分析
    return null;
}

private final Node<K,V>[] initTable() {
	Node<K,V>[] tab; int sc;
	//为什么是个while?
	//有可能多个线程同时调用此方法,只要有一个线程成功,那么就可以return了
	while ((tab = table) == null || tab.length == 0) {
	    if ((sc = sizeCtl) < 0)
	    	//让出CPU执行片,让其它线程执行
	        Thread.yield(); // lost initialization race; just spin
	    //sc = sizeCtl, 而sizeCtl为成员变量,默认为0
	    //(乐观锁)如果SIZECTL==sc,那么SIZECTL赋值为-1
	    //由于SIZECTL初始值为0,如果此处有两个线程同时进入,那么先到的线程就会将SIZECTL赋值为-1
	    //(也就是内存中的sizeCtl也被赋值为-1),
	    //那么后面的线程发现SIZECTL != sc,那么U.compareAndSwapInt()返回false,就不会执行了
	    //SIZECTL==0,还未初始化(默认状态);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;
	                @SuppressWarnings("unchecked")
	                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
	                table = tab = nt;
	                //sc=16-4=12=16*0.75(扩容因子)
	                sc = n - (n >>> 2);
	            }
	        } finally {
	        	//sizeCtl(SIZECTL)的值也为12,之前分别为0,-1
	            sizeCtl = sc;
	        }
	        break;
	    }
	}
	return tab;
}

addCount(1L, binCount)方法分析

private final void addCount(long x, int check) {
	//CounterCell[]:标记Map大小,分片的方式(每个元素负责一片区域的大小,Map总大小就是每片大小sum)
	CounterCell[] as; long b, s;
	//counterCells[]未初始化,或者CAS失败
	if ((as = counterCells) != null ||
	    !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
	    CounterCell a; long v; int m;
	    boolean uncontended = true;
	    //counterCells[]未初始化
	    //或者
	    //ThreadLocalRandom.getProbe()产生随机数(跟Random类似),*.getProbe() & m <= m
	    if (as == null || (m = as.length - 1) < 0 ||
	        (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
	        !(uncontended =
	          U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
	        //根据"||"的运算性质,下述4种情况将会执行扩容fullAddCount():初始化CounterCell[]
	        //1.as == null
	        //2.as != null && (m = as.length - 1) < 0
	        //3.as != null && (m = as.length - 1) >= 0 &&
	        //  (a = as[ThreadLocalRandom.getProbe() & m]) == null
	        //4.as != null && (m = as.length - 1) >= 0 &&
	        //  (a = as[ThreadLocalRandom.getProbe() & m]) != null && CAS失败
	        fullAddCount(x, uncontended);	//见下文分析
	        return;
	    }
	    if (check <= 1)
	        return;
	    s = sumCount();
	}
	if (check >= 0) {
	    Node<K,V>[] tab, nt; int n, sc;
	    while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
	           (n = tab.length) < MAXIMUM_CAPACITY) {
	        //针对每个n会生成唯一的戳(由于n的取值为2^n)
	        //当n=16时,返回1000 0000 0001 1011
	        int rs = resizeStamp(n);
	        //sc = sizeCtl,故此时有另一个线程正在初始化
	        //首次执行的时候sc不满足<0,会执行else if(...)逻辑,随后才会执行此if(...)逻辑
	        if (sc < 0) {
	            if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
	                sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
	                transferIndex <= 0)
	                break;
		        //对比下述+2的代码,此处+1表示又增加了1个线程在操作
	            if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
	                transfer(tab, nt);	//具体分析见下文
	        }
	        //当n=16时,此时左移16位为
	        //1000 0000 0001 1011 0000 0000 0000 0000(由于int为32位,故是一个负数)
	        //hex: -2145714176
	        //+2 ->
	        //1000 0000 0001 1011 0000 0000 0000 0010
	        //hex: -2145714174
	        //+2表示有1个线程在操作
	        else if (U.compareAndSwapInt(this, SIZECTL, sc,
	                                     (rs << RESIZE_STAMP_SHIFT) + 2))	
	            transfer(tab, null);//具体分析见下文(与上面此方法调用不同,这儿第二个参数为null)
	        s = sumCount();
	    }
	}
}

private final void fullAddCount(long x, boolean wasUncontended) {
  int h;
  if ((h = ThreadLocalRandom.getProbe()) == 0) {
      ThreadLocalRandom.localInit();      // force initialization
      h = ThreadLocalRandom.getProbe();
      wasUncontended = true;
  }
  boolean collide = false;                // True if last slot nonempty
  for (;;) {
      CounterCell[] as; CounterCell a; int n; long v;
      //CountCell[]已经被初始化
      if ((as = counterCells) != null && (n = as.length) > 0) {
      	  //该随机位置为null[(n - 1) & h <= (n - 1)],则放到该位置
          if ((a = as[(n - 1) & h]) == null) {
              if (cellsBusy == 0) {            // Try to attach new Cell
                  CounterCell r = new CounterCell(x); // Optimistic create
                  //占位,只允许一个线程进入
                  if (cellsBusy == 0 &&
                      U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
                      boolean created = false;
                      try {               // Recheck under lock
                          CounterCell[] rs; int m, j;
                          if ((rs = counterCells) != null &&
                              (m = rs.length) > 0 &&
                              rs[j = (m - 1) & h] == null) {
                              rs[j] = r; //将CounterCell r实例放到该位置
                              created = true;
                          }
                      } finally {
                          cellsBusy = 0;
                      }
                      if (created)
                          break;
                      //没有created成功,继续for(;;)
                      continue;           // Slot is now non-empty
                  }
              }
              collide = false;
          }
          //addCount()方法CAS失败后wasUncontended = false,将其改为true,继续for(;;)
          else if (!wasUncontended)       // CAS already known to fail
              wasUncontended = true;      // Continue after rehash
          //已经有值,直接再其基础上增加x即可
          else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
              break;
          //有其它线程更改了as导致其!= counterCells,或者n大于CPU的核心数(并发数不会大于CPU核数)
          else if (counterCells != as || n >= NCPU)
              collide = false;            // At max size or stale(stable:不再变化的意思)
          //上面讲collide改为false,为何此处又要改为true???
          else if (!collide)
              collide = true;
          //CAS占位,扩容counterCells.size * 2
          else if (cellsBusy == 0 &&
                   U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
              try {
                  if (counterCells == as) {// Expand table unless stale
                      CounterCell[] rs = new CounterCell[n << 1];	//原容量 * 2
                      //数据迁移
                      for (int i = 0; i < n; ++i)
                          rs[i] = as[i];
                      counterCells = rs;
                  }
              } finally {
                  cellsBusy = 0;
              }
              collide = false;
              //仅仅完成了扩容,但是要add的(long) x还未放入,需后续自旋来实现
              continue;                   // Retry with expanded table
          }
          h = ThreadLocalRandom.advanceProbe(h);
      }
      //CountCell[]未初始化,初始化之
      //cellsBusy(默认为0)功能与之前的sizeCtl类似,
      //进入此if就代表此线程占用了此操作,从而阻止其它线程进入(相当于加锁Lock,但比Lock效率高)
      else if (cellsBusy == 0 && counterCells == as &&
               U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
          boolean init = false;
          try {                           // Initialize table
              //再判断一次counterCells == as
              if (counterCells == as) {
                  CounterCell[] rs = new CounterCell[2];
                  rs[h & 1] = new CounterCell(x);	//h & 1 <= 1(0, 1)
                  counterCells = rs;	//将rs赋值给全局变量counterCells
                  init = true;	//初始化完成
              }
          } finally {
              cellsBusy = 0;	//释放锁
          }
          //初始化成功,跳出自旋for (;;)
          if (init)
              break;
      }
      //并发性高,直接将x放到baseCount中
      else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
          break;                          // Fall back on using base
  }
}
//扩容(其中涉及到数据的迁移)
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
    int n = tab.length, stride;
    //计算 CPU 核心数和 Map 数组的长度得到每个线程(CPU)要帮助处理多少个桶,
    //并且这里每个线程处理都是平均的。默认每个线程处理 16 个桶。因此,如果长度是16的时候,
    //扩容的时候只会有一个线程扩容
    //stride至少为16,也可以是更大的值(如32,64...)
    if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
        stride = MIN_TRANSFER_STRIDE; // subdivide range
    //初始化nextTab[],长度为2 * tab.length()
    if (nextTab == null) {            // initiating
        try {
            @SuppressWarnings("unchecked")
            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
            nextTab = nt;
        } catch (Throwable ex) {      // try to cope with OOME
            sizeCtl = Integer.MAX_VALUE;
            return;
        }
        nextTable = nextTab;
        transferIndex = n;
    }
    int nextn = nextTab.length;
    //该节点的hash==MOVED
    ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
    boolean advance = true;
    boolean finishing = false; // to ensure sweep before committing nextTab
    for (int i = 0, bound = 0;;) {
        Node<K,V> f; int fh;
        //换分区间,不同线程处理不同的桶位,如
        //线程A:00~15
        //线程B:16~31
        //...
        while (advance) {
            int nextIndex, nextBound;
            //一般不会进入
            if (--i >= bound || finishing)
                advance = false;
            //一般不会进入
            else if ((nextIndex = transferIndex) <= 0) {
                i = -1;
                advance = false;
            }
            //假设nextIndex=16
            //TRANSFERINDEX会被改成0,也就是说需要转移的数据为0(也就是任务被领取了)
            //因此advance = false,也就会跳出for(...)自旋
            else if (U.compareAndSwapInt
                     (this, TRANSFERINDEX, nextIndex,
                      nextBound = (nextIndex > stride ?
                                   nextIndex - stride : 0))) {
                bound = nextBound;	//16
                i = nextIndex - 1;	//i = 15
                advance = false;
            }
        }
        if (i < 0 || i >= n || i + n >= nextn) {
            int sc;
            //扩容完毕
            if (finishing) {
                nextTable = null;
                table = nextTab;	//新桶,容量为32
                sizeCtl = (n << 1) - (n >>> 1);	//sizeCtl = 16 << 1 - 16 >>> 1 = 24
                return;
            }
            if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
            	//代表还有其它线程在扩容
                if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                    return;
                //其它线程扩容完成,这是最后一个扩容线程,故finishing = true
                finishing = advance = true;
                i = n; // recheck before commit
            }
        }
        //用ForwardingNode<K,V> fwd来占位
        else if ((f = tabAt(tab, i)) == null)
            advance = casTabAt(tab, i, null, fwd);
        //其它线程正在进行处理
        else if ((fh = f.hash) == MOVED)
            advance = true; // already processed
        //加锁,开始扩容
        else {
            synchronized (f) {
                if (tabAt(tab, i) == f) {
                    Node<K,V> ln, hn;
                    if (fh >= 0) {
                    	//fh = f.hash,跟之前HashMap类似,& n后要么为0,要么为1
                    	//扩容之后,原来位于同一桶位的链表元素会拆分到两个地方,原位置,原位置+n
                    	//假设原大小为16,那么n=16
	                	//那么table[15]的链表会拆分到table[15]与table[31]
	                	//table[15]链表中的元素hash值可能为0 1111 OR 1 1111,
	                	//& 1 0000(16)也就有两种情况:0、1
                        int runBit = fh & n;	//首节点hash & n
                        Node<K,V> lastRun = f;
                        for (Node<K,V> p = f.next; p != null; p = p.next) {
                            int b = p.hash & n;
                            //该节点与首节点的桶位不同(因此该节点属于hn)
                            if (b != runBit) {
                                runBit = b;
                                //保证后面的节点与自己的取于值相同,避免后面没有必要的循环
                                //要不都是hn,要不都是ln
                                lastRun = p;	
                            }
                        }
                        if (runBit == 0) {
                            ln = lastRun;
                            hn = null;
                        }
                        else {
                            hn = lastRun;
                            ln = null;
                        }
                        //创建链表hn,ln
                        for (Node<K,V> p = f; p != lastRun; p = p.next) {
                            int ph = p.hash; K pk = p.key; V pv = p.val;
                            if ((ph & n) == 0)
                                ln = new Node<K,V>(ph, pk, pv, ln);
                            else
                                hn = new Node<K,V>(ph, pk, pv, hn);
                        }
                        //将创建好的链表分别放到桶的高位、低位中
                        setTabAt(nextTab, i, ln)
                        setTabAt(nextTab, i + n, hn);
                        setTabAt(tab, i, fwd);	//将桶位中设置为fwd,表示此节点已经处理完毕
                        advance = true;	//干完一个桶,继续想后推进
                    }
                    //红黑树的处理流程
                    else if (f instanceof TreeBin) {
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        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;
                            TreeNode<K,V> p = new TreeNode<K,V>
                                (h, e.key, e.val, null, null);
                            if ((h & n) == 0) {
                                if ((p.prev = loTail) == null)
                                    lo = p;
                                else
                                    loTail.next = p;
                                loTail = p;
                                ++lc;
                            }
                            else {
                                if ((p.prev = hiTail) == null)
                                    hi = p;
                                else
                                    hiTail.next = p;
                                hiTail = p;
                                ++hc;
                            }
                        }
                        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;
                        setTabAt(nextTab, i, ln);
                        setTabAt(nextTab, i + n, hn);
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值