ConcurrentHashMap 总结( 中 )

前端之家收集整理的这篇文章主要介绍了ConcurrentHashMap 总结( 中 )前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

转自:nofollow">https://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651479108&idx=2&sn=789a75c75a84f8bf49e9fc40f1b40c62&chksm=bd25303b8a52b92d8a3aba1270d51d2d0a1667d2ebc9858418ff4279c114ac462896d58afc4e&mpshare=1&scene=23&srcid=0925Fr0mdZ0GSMXPbhANyt6o#rd

<blockquote style="border-left-width:3px;border-left-style:solid;border-left-color:rgb(219,219,219);color:rgb(62,62,62);font-family:'Helvetica Neue',Helvetica,'Hiragino Sans GB','Microsoft YaHei',Arial,sans-serif;font-size:16px;">
<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136,136);">/*


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">   
一个过渡的table表  只有在扩容的时候才会使用


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">    /


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">   private transient volatile Node<K,V>[] nextTable;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);"> 


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">   
Moves and/or copies the nodes in each bin to new table. See


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">    * above for explanation.


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">   private final void transfer(Node<K,V>[] tab,Node<K,V>[] nextTab) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       int n = tab.length,stride;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       if ((stride = (NCPU > 1) ? (n >>> 3) / Ncpu : n) < MIN_TRANSFER_STRIDE)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           stride = MIN_TRANSFER_STRIDE; // subdivide range


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       if (nextTab == null) {            // initiating


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           try {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               @SuppressWarnings("unchecked")


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];//构造一个nextTable对象 它的容量是原来的两倍


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               nextTab = nt;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           } catch (Throwable ex) {      // try to cope with OOME


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               sizeCtl = Integer.MAX_VALUE;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               return;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           nextTable = nextTab;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           transferIndex = n;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       int nextn = nextTab.length;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);//构造一个连节点指针 用于标志位


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       boolean advance = true;//并发扩容的关键属性 如果等于true 说明这个节点已经处理过


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       boolean finishing = false; // to ensure sweep before committing nextTab


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">       for (int i = 0,bound = 0;;) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           Node<K,V> f; int fh;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           //这个while循环体的作用就是在控制i--  通过i--可以依次遍历原hash表中的节点


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           while (advance) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               int nextIndex,nextBound;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               if (--i >= bound || finishing)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   advance = false;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               else if ((nextIndex = transferIndex) <= 0) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   i = -1;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               else if (U.compareAndSwapInt


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                        (this,TRANSFERINDEX,nextIndex,


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                         nextBound = (nextIndex > stride ?


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                      nextIndex - stride : 0))) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   bound = nextBound;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   i = nextIndex - 1;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           if (i < 0 || i >= n || i + n >= nextn) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               int sc;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               if (finishing) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   //如果所有的节点都已经完成复制工作  就把nextTable赋值给table 清空临时对象nextTable


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   nextTable = null;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   table = nextTab;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   sizeCtl = (n << 1) - (n >>> 1);//扩容阈值设置为原来容量的1.5倍  依然相当于现在容量的0.75倍


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   return;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               //利用CAS方法更新这个扩容阈值,在这里面sizectl值减一,说明新加入一个线程参与到扩容操作


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               if (U.compareAndSwapInt(this,SIZECTL,sc = sizeCtl,sc - 1)) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       return;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   finishing = advance = true;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   i = n; // recheck before commit


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           //如果遍历到的节点为空 则放入ForwardingNode指针


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           else if ((f = tabAt(tab,i)) == null)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               advance = casTabAt(tab,i,null,fwd);


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           //如果遍历到ForwardingNode节点  说明这个点已经被处理过了 直接跳过  这里是控制并发扩容的核心


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           else if ((fh = f.hash) == MOVED)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               advance = true; // already processed


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">           else {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   //节点上锁


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">               synchronized (f) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   if (tabAt(tab,i) == f) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       Node<K,V> ln,hn;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       //如果fh>=0 证明这是一个Node节点


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       if (fh >= 0) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           int runBit = fh & n;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           //以下的部分在完成的工作是构造两个链表  一个是原链表  另一个是原链表的反序排列


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           Node<K,V> lastRun = f;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           for (Node<K,V> p = f.next; p != null; p = p.next) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               int b = p.hash & n;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               if (b != runBit) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   runBit = b;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   lastRun = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           if (runBit == 0) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               ln = lastRun;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               hn = null;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           else {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               hn = lastRun;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               ln = null;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,V> p = f; p != lastRun; p = p.next) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               int ph = p.hash; K pk = p.key; V pv = p.val;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               if ((ph & n) == 0)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   ln = new Node<K,V>(ph,pk,pv,ln);


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               else


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   hn = new Node<K,hn);


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           //在nextTable的i位置上插入一个链表


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           setTabAt(nextTab,136);">                           //在nextTable的i+n的位置上插入另一个链表


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,i + n,136);">                           //在table的i位置上插入forwardNode节点  表示已经处理过该节点


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           setTabAt(tab,136);">                           //设置advance为true 返回到上面的while循环中 就可以执行i--操作


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           advance = true;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       //对TreeBin对象进行处理  与上面的过程类似


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                       else if (f instanceof TreeBin) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           TreeBin<K,V> t = (TreeBin<K,V>)f;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           TreeNode<K,V> lo = null,loTail = null;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,V> hi = null,hiTail = null;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           int lc = 0,hc = 0;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           //构造正序和反序两个链表


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,V> e = t.first; e != null; e = e.next) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               int h = e.hash;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               TreeNode<K,V> p = new TreeNode<K,V>


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   (h,e.key,e.val,null);


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               if ((h & n) == 0) {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   if ((p.prev = loTail) == null)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                       lo = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   else


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                       loTail.next = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   loTail = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   ++lc;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               else {


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   if ((p.prev = hiTail) == null)


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                       hi = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                       hiTail.next = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   hiTail = p;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                                   ++hc;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           //如果扩容后已经不再需要tree的结构 反向转换为链表结构


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               (hc != 0) ? new TreeBin<K,V>(lo) : t;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                           hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                               (lc != 0) ? new TreeBin<K,V>(hi) : t;


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                            //在nextTable的i位置上插入一个链表    


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                            //在table的i位置上插入forwardNode节点  表示已经处理过该节点


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">                   }


<p style="clear:both;min-height:1em;">
<span style="font-size:12px;color:rgb(136,136);">   }

<p style="clear:both;min-height:1em;color:rgb(62,sans-serif;font-size:16px;">

方法

方法做铺垫。ConcurrentHashMap最常用的就是put和get两个方法。现在来介绍put方法,这个put方法依然沿用HashMap的put方法的思想,根据hash值计算这个新插入的点在table中的位置i,如果i位置是空的,直接放进去,否则进行判断,如果i位置是树节点,按照树的方式插入新的节点,否则把i插入到链表的末尾。ConcurrentHashMap中依然沿用这个思想,有一个最重要的不同点就是ConcurrentHashMap不允许key或value为null值。另外由于涉及到多线程,put方法就要复杂一点。在多线程中可能有以下两个情况

    方法中在空结点上插入forward节点,如果检测到需要插入的位置被forward节点占有,就帮助进行扩容;

方法对key的hashcode进行一次hash计算,由此来确定这个值在table中的位置。

0),则得到的结点就是hash值相同的节点组成的链表的头节点。需要依次向后遍历确定这个新加入的值所在位置。如果遇到hash值与key值都与新加入节点是一致的情况,则只需要更新value值即可。否则依次向后遍历,直到链表尾插入这个结点。如果加入这个节点以后链表长度大于8,就把这个链表转换成红黑树。如果这个节点的类型已经是树节点的话,直接调用树节点的插入方法进行插入新的值。

[] tab = table;;) {

f; int n,fh;

(hash,key,null)))

= 0) {

e = f;; ++binCount) {

修改对应结点的value值

pred = e;

p;

)f).putTreeVal(hash,136);">                                                           value)) != null) {

= TREEIFY_THRESHOLD)

数量+1

2.6.1 helpTransfer方法

方法。这个方法调用的时候,当前ConcurrentHashMap一定已经有了nextTable对象,首先拿到这个nextTable对象,调用transfer方法。回看上面的transfer方法可以看到,当本线程进入扩容方法的时候会直接进入复制阶段。

2.6.2 treeifyBin方法

方法用于将过长的链表转换为TreeBin对象。但是他并不是直接转换,而是进行一次容量判断,如果容量没有达到转换的要求,直接进行扩容操作并返回;如果满足条件才链表的结构抓换为TreeBin ,这与HashMap不同的是,它并没有把TreeNode直接放入红黑树,而是利用了TreeBin这个小容器来封装所有的TreeNode.

方法

方法比较简单,给定一个key来确定value的时候,必须满足两个条件  key相同  hash值相同,对于节点可能在链表或树上的情况,需要分别去查找。

[] tab; Node e,p; int n,eh; K ek;

0 &&

搜索到的节点key与传入的key相同且不为null,直接返回这个节点  

猜你在找的Java相关文章