ConcurrentHashMap源码
Posted da-peng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ConcurrentHashMap源码相关的知识,希望对你有一定的参考价值。
putval源码
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; //如果table还没有初始化 if (tab == null || (n = tab.length) == 0) tab = initTable(); //传入参数tab类与偏移地址(n-1)&hash,通过CAS方法获取对应目标的值,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 没有锁,如果是空bin的话 } //如果在进行扩容,则先进行扩容操作?????????????????????????????? else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); //hash冲突 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; //找到相同的key 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; //没找到相同的key,在最后加上新节点 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) //根据table,和偏移量转换一个桶子后面的链表为红黑树 treeifyBin(tab, i); //返回旧的value值 if (oldVal != null) return oldVal; break; } } } //统计size,并且检查是否需要扩容 addCount(1L, binCount); return null; }
inittable()
private final Node<K,V>[] initTable() { Node<K,V>[] tab; int sc; //检查是否为空 while ((tab = table) == null || tab.length == 0) { if ((sc = sizeCtl) < 0) //sizeCtl<0表示其他线程已经在初始化了或者扩容了,挂起当前线程 Thread.yield(); // lost initialization race; just spin else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { //将SIZECTL置为-1,表示有一个线程正在初始化table 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 = n - (n >>> 2); } } finally { sizeCtl = sc; } break; } } return tab; }
以上是关于ConcurrentHashMap源码的主要内容,如果未能解决你的问题,请参考以下文章