ConcurrentHashMap原始碼分析--Java8
private transient volatile Node<K,V>[] nextTable; //僅僅在擴容使用,並且此時非空
// 將table每一個bin(桶位)的Node移動或複製到nextTable // 只在addCount(long x, int check)、helpTransfer、tryPresize中呼叫 private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) { int n = tab.length, stride; // 每核處理的量小於16,則強制賦值16 if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) stride = MIN_TRANSFER_STRIDE; // subdivide range 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; //連節點指標,標誌位,fwd的hash值為-1,fwd.nextTable=nextTab。 ForwardingNode<K,V> fwd= new ForwardingNode<K,V>(nextTab); boolean advance= true;//併發擴容的關鍵屬性,等於true,說明此節點已經處理過 boolean finishing = false; // to ensure sweep before committing nextTab for (int i = 0, bound = 0;;) { // 死迴圈 Node<K,V> f; int fh; while (advance) { // 控制--i,遍歷原hash表中的節點 int nextIndex, nextBound; if (--i >= bound || finishing) advance = false; else if ((nextIndex = transferIndex) <= 0) { i = -1; advance = false; }//TRANSFERINDEX 即用CAS計算得到的transferIndex else if (U.compareAndSwapInt (this, TRANSFERINDEX, nextIndex, nextBound = (nextIndex > stride ? nextIndex - stride : 0))) { bound = nextBound; i = nextIndex - 1; advance = false; } } if (i < 0 || i >= n || i + n >= nextn) { int sc; if (finishing) { // 所有節點複製完畢 nextTable = null; table = nextTab; sizeCtl = (n << 1) - (n >>> 1); //擴容閥值設為原來的1.5倍,即現在的0.75倍 return; // 僅有的2個跳出死迴圈出口之一 }//CAS更新擴容閾值,sc-1表明新加入一個執行緒參與擴容 if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) { if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT) return;// 僅有的2個跳出死迴圈出口之一 finishing = advance = true; i = n; // recheck before commit } } else if ((f = tabAt(tab, i)) == null) //該節點為空,則插入ForwardingNode advance = casTabAt(tab, i, null, fwd); //遍歷到ForwardingNode節點,說明此節點被處理過了,直接跳過。這是控制併發擴容的核心 else if ((fh = f.hash) == MOVED) // MOVED=-1,hash for fwd advance = true; // already processed else { synchronized (f) { //上鎖 if (tabAt(tab, i) == f) { Node<K,V> ln, hn; //ln原位置節點,hn新位置節點 if (fh >= 0) { // 連結串列 int runBit = fh & n; // f.hash & n Node<K,V> lastRun = f; // lastRun和p兩個連結串列,逆序?? for (Node<K,V> p = f.next; p != null; p = p.next) { int b = p.hash & n; // f.next.hash & n if (b != runBit) { runBit = b; lastRun = p; } } if (runBit == 0) { ln = lastRun; hn = null; } else { hn = lastRun; ln = null; } 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) // 和HashMap確定擴容後的節點位置一樣 ln = new Node<K,V>(ph, pk, pv, ln); else hn = new Node<K,V>(ph, pk, pv, hn); //新位置節點 }//類似HashMap,為何i+n?參見HashMap的筆記 setTabAt(nextTab, i, ln);//在nextTable[i]插入原節點 setTabAt(nextTab, i + n, hn);//在nextTable[i+n]插入新節點 //在nextTable[i]插入forwardNode節點,表示已經處理過該節點 setTabAt(tab, i, fwd); //設定advance為true 返回到上面的while迴圈中 就可以執行--i操作 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; //lc、hc=0兩計數器分別++記錄原、新bin中TreeNode數量 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; } }//擴容後樹節點個數若<=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; setTabAt(nextTab, i, ln); setTabAt(nextTab, i + n, hn); setTabAt(tab, i, fwd); advance = true; } } } } } }
相關推薦
ConcurrentHashMap原始碼分析--Java8
private transient volatile Node<K,V>[] nextTable; //僅僅在擴容使用,並且此時非空 // 將table每一個bin(桶位)的Node移動或複製到nextTable // 只在addCount(long x, int check)、helpTr
JDK1.8 ConcurrentHashMap原始碼分析
文章目錄 ConcurrentHashMap資料結構 類的繼承關係 類的內部類 重要的屬性 類的建構函式 ConcurrentHashMap()型建構函式 ConcurrentHashMap(i
ConcurrentHashMap原始碼分析
本篇部落格的目錄: 一:put方法原始碼 二:get方法原始碼 三:rehash的過程 四:總結 一:put方法的原始碼 首先,我們來看一下segment內部類中put方法的原始碼,這個方法它是segment片組的,也就是我們在用concurrentHash的p
【原始碼閱讀系列】JDK 8 ConcurrentHashMap 原始碼分析之 由transfer引發的bug
不閱讀原始碼就不會發現這個事兒 前段時間在閱讀ConcurrentHashMap原始碼,版本JDK 8,目前原始碼研究已經告一段落。感謝魯道的ConcurrentHashMap原始碼分析文章,讀到文章,感覺和作者發生了一些交流,解答了很多疑惑,也驗證了一些想法。魯道在簡書的addCount分析文章點這裡&n
(Map) HashMap、LinkedHashMap、ConcurrentHashMap原始碼分析
前言 聽說Hashtabe、HashMap、LinkedHashMap、ConcurrentHashMap面試被問較多,平時也會去注意,但畢竟還是要自己看看原始碼,這樣才能在開發過程中選擇最合適的資料結構,簡單來說, HashMap:陣列+單鏈表,陣列(桶,
ArrayList原始碼分析-java8
1.特點總結: 可儲存元素null 呼叫無參構造器建立例項,預設容量capacity=10 自動擴容倍數:1.5 和Vector類等價,區別是 ArrayList不是執行緒安全的. 4個重要的private static final型別
Set介面原始碼分析-java8
1.toArray()和toArray(T[] a) 將set例項轉為String[]的方式如下: Set<String> x=new HashSet<String>; String[] y = x.toArray(new S
【java基礎之ConcurrentHashMap原始碼分析】
概述: ConcurrentHashMap這個類在java.lang.current包中,這個包中的類都是執行緒安全的。Conc
多執行緒高併發程式設計(10) -- ConcurrentHashMap原始碼分析
一.背景 前文講了HashMap的原始碼分析,從中可以看到下面的問題: HashMap的put/remove方法不是執行緒安全的,如果在多執行緒併發環境下,使用synchronized進行加鎖,會導致效率低下; 在遍歷迭代獲取時進行修改(put/remove)操作,會導致發生併發修改異常(Concu
【Java8原始碼分析】併發包-ConcurrentHashMap(一)
一、CAS原理簡介 Java8中,ConcurrentHashMap摒棄了Segment的概念,而是啟用了一種全新的方式實現:利用CAS演算法。它沿用了HashMap的思想,底層依然由“陣列”+連結串列+紅黑樹的方式實現。 那什麼CAS演算法呢?以前採用鎖的
Java原始碼分析——ConcurrentHashMap
HashMap在高併發情況下新增值容易出現環形鏈,不能保證資料的安全性,所以ConcurrentHashMap作為替代方式出現了,concurrentHashmap比hashtable更加高效,因為hashtable是將整個物件鎖住,當一個執行緒在操作時,其它執行緒不能有任何操作。
ConcurrentHashMap與紅黑樹實現分析Java8
本文學習知識點 1、二叉查詢樹,以及二叉樹查詢帶來的問題。 2、平衡二叉樹及好處。 3、紅黑樹的定義及構造。 4、ConcurrentHashMap中紅黑樹的構造。 在正式分析紅黑樹之前,有必要了解紅黑樹的發展過程,請讀者耐心閱讀。 二叉查詢樹 紅黑樹的起源得從二叉查詢
HashMap、ConcurrentHashMap實現原理及原始碼分析
HashMap:https://www.cnblogs.com/chengxiao/p/6059914.html ConcurrentHashMap:https://blog.csdn.net/dingjianmin/article/details/79776646 遺留問
ConcurrentHashMap JDK1.8中結構原理及原始碼分析
注:本文根據網路和部分書籍整理基於JDK1.7書寫,如有雷同敬請諒解 歡迎指正文中的錯誤之處。 資料結構 ConcurrentHashMap 1.8 拋棄了Segment分段鎖機制,採用Node + CAS + Synchronized來保證併發安全進行實現
【java基礎】ConcurrentHashMap實現原理及原始碼分析
ConcurrentHashMap是Java併發包中提供的一個執行緒安全且高效的HashMap實現(若對HashMap的實現原理還不甚瞭解,可參考我的另一篇文章),ConcurrentHashMap在併發程式設計的場景中使用頻率非常之高,本文就來分析下Concurre
ConcurrentHashMap實現原理及原始碼分析
ConcurrentHashMap是Java併發包中提供的一個執行緒安全且高效的HashMap實現(若對HashMap的實現原理還不甚瞭解,可參考我的另一篇文章),ConcurrentHashMap在併發程式設計的場景中使用頻率非常之高,本文就來分析下Concurrent
ConcurrentHashMap鎖分段技術原始碼分析
一、背景: 執行緒不安全的HashMap 因為多執行緒環境下,使用Hashmap進行put操作會引起死迴圈,導致CPU利用率接近100%,所以在併發情況下不能使用HashMap。 效率低下的HashTable容器 HashTable容器使用syn
JUC原始碼分析-集合篇(一):ConcurrentHashMap
ConcurrentHashMap 是一個支援併發檢索和併發更新的執行緒安全的HashMap(但不允許空key或value)。不管是在實際工作或者是面試中,ConcurrentHashMap 都是在整個JUC集合框架裡出現頻率最高的一個類,所以,對ConcurrentHas
JDK原始碼分析系列--ConcurrentHashMap(1.8)
定義變數 /** * node陣列最大容量 */ private static final int MAXIMUM_CAPACITY = 1 << 30; /** * 預設容量 */ pr
HashMap, ConcurrentHashMap 最詳細的原理及原始碼分析
網上關於 HashMap 和 ConcurrentHashMap 的文章確實不少,不過缺斤少兩的文章比較多,所以才想自己也寫一篇,把細節說清楚說透,尤其像 Java8 中的 ConcurrentHashMap,大部分文章都說不清楚。 終歸是希望能降低大家學習的成本,不希望大家到處找各種不是很