CopyOnWriteArrayList源码解析
此文已由作者趙計(jì)剛授權(quán)網(wǎng)易云社區(qū)發(fā)布。
歡迎訪問網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營經(jīng)驗(yàn)。
注:在看這篇文章之前,如果對(duì)HashMap的層不清楚的話,建議先去看看HashMap源碼解析。
http://www.cnblogs.com/java-zhao/p/5106189.html
1、對(duì)于ConcurrentHashMap需要掌握以下幾點(diǎn)
Map的創(chuàng)建:ConcurrentHashMap()
往Map中添加鍵值對(duì):即put(Object key, Object value)方法
獲取Map中的單個(gè)對(duì)象:即get(Object key)方法
刪除Map中的對(duì)象:即remove(Object key)方法
判斷對(duì)象是否存在于Map中:containsKey(Object key)
遍歷Map中的對(duì)象:即keySet().iterator(),在實(shí)際中更常用的是增強(qiáng)型的for循環(huán)去做遍歷
2、ConcurrentHashMap的創(chuàng)建
注:在往下看之前,心里先有這樣一個(gè)映像:ConcurrentHashMap的數(shù)據(jù)結(jié)構(gòu):一個(gè)指定個(gè)數(shù)的Segment數(shù)組,數(shù)組中的每一個(gè)元素Segment相當(dāng)于一個(gè)HashTable。
2.1、使用方法:
Map<String,?Object>?map?=?new?ConcurrentHashMap<String,?Object>();2.2、源代碼:
?ConcurrentHashMap相關(guān)屬性:
????/***?用于分段*///?根據(jù)這個(gè)數(shù)來計(jì)算segment的個(gè)數(shù),segment的個(gè)數(shù)是僅小于這個(gè)數(shù)且是2的幾次方的一個(gè)數(shù)(ssize)static?final?int?DEFAULT_CONCURRENCY_LEVEL?=?16;//?最大的分段(segment)數(shù)(2的16次方)static?final?int?MAX_SEGMENTS?=?1?<<?16;/***?用于HashEntry*///?默認(rèn)的用于計(jì)算Segment數(shù)組中的每一個(gè)segment的HashEntry[]的容量,但是并不是每一個(gè)segment的HashEntry[]的容量static?final?int?DEFAULT_INITIAL_CAPACITY?=?16;//?默認(rèn)的加載因子(用于resize)static?final?float?DEFAULT_LOAD_FACTOR?=?0.75f;//?用于計(jì)算Segment數(shù)組中的每一個(gè)segment的HashEntry[]的最大容量(2的30次方)static?final?int?MAXIMUM_CAPACITY?=?1?<<?30;/***?segments數(shù)組*?每一個(gè)segment元素都看做是一個(gè)HashTable*/final?Segment<K,?V>[]?segments;/***?用于擴(kuò)容*/final?int?segmentMask;//?用于根據(jù)給定的key的hash值定位到一個(gè)Segmentfinal?int?segmentShift;//?用于根據(jù)給定的key的hash值定位到一個(gè)SegmentSegment類(ConcurrentHashMap的內(nèi)部類)
????/***?一個(gè)特殊的HashTable*/static?final?class?Segment<K,?V>?extends?ReentrantLock?implementsSerializable?{private?static?final?long?serialVersionUID?=?2249069246763182397L;transient?volatile?int?count;//?該Segment中的包含的所有HashEntry中的key-value的個(gè)數(shù)transient?int?modCount;//?并發(fā)標(biāo)記/**?元素個(gè)數(shù)超出了這個(gè)值就擴(kuò)容?threshold==(int)(capacity?*?loadFactor)*?值得注意的是,只是當(dāng)前的Segment擴(kuò)容,所以這是Segment自己的一個(gè)變量,而不是ConcurrentHashMap的*/transient?int?threshold;transient?volatile?HashEntry<K,?V>[]?table;//?鏈表數(shù)組final?float?loadFactor;/***?這里要注意一個(gè)很不好的編程習(xí)慣,就是小寫l,容易與數(shù)字1混淆,所以最好不要用小寫l,可以改為大寫L*/Segment(int?initialCapacity,?float?lf)?{loadFactor?=?lf;//每個(gè)Segment的加載因子setTable(HashEntry.<K,?V>?newArray(initialCapacity));}/***?創(chuàng)建一個(gè)Segment數(shù)組,容量為i*/@SuppressWarnings("unchecked")static?final?<K,?V>?Segment<K,?V>[]?newArray(int?i)?{return?new?Segment[i];}/***?Sets?table?to?new?HashEntry?array.?Call?only?while?holding?lock?or?in*?constructor.*/void?setTable(HashEntry<K,?V>[]?newTable)?{threshold?=?(int)?(newTable.length?*?loadFactor);//?設(shè)置擴(kuò)容值table?=?newTable;//?設(shè)置鏈表數(shù)組}說明:只列出了Segement的全部屬性和創(chuàng)建ConcurrentHashMap時(shí)所用到的方法。
HashEntry類(ConcurrentHashMap的內(nèi)部類)
????/***?Segment中的HashEntry節(jié)點(diǎn)?類比HashMap中的Entry節(jié)點(diǎn)*/static?final?class?HashEntry<K,?V>?{final?K?key;//?鍵final?int?hash;//hash值volatile?V?value;//?實(shí)現(xiàn)線程可見性final?HashEntry<K,?V>?next;//?下一個(gè)HashEntryHashEntry(K?key,?int?hash,?HashEntry<K,?V>?next,?V?value)?{this.key?=?key;this.hash?=?hash;this.next?=?next;this.value?=?value;}/**?創(chuàng)建HashEntry數(shù)組,容量為傳入的i*/@SuppressWarnings("unchecked")static?final?<K,?V>?HashEntry<K,?V>[]?newArray(int?i)?{return?new?HashEntry[i];}}ConcurrentHashMap(int initialCapacity,float loadFactor,int concurrencyLevel)
?1?????/**2??????*?創(chuàng)建ConcurrentHashMap3??????*?@param?initialCapacity?用于計(jì)算Segment數(shù)組中的每一個(gè)segment的HashEntry[]的容量,?但是并不是每一個(gè)segment的HashEntry[]的容量4??????*?@param?loadFactor5??????*?@param?concurrencyLevel?用于計(jì)算Segment數(shù)組的大小(可以傳入不是2的幾次方的數(shù),但是根據(jù)下邊的計(jì)算,最終segment數(shù)組的大小ssize將是2的幾次方的數(shù))6??????*?7??????*?步驟:8??????*?這里以默認(rèn)的無參構(gòu)造器參數(shù)為例,initialCapacity==16,loadFactor==0.75f,concurrencyLevel==169??????*?1)檢查各參數(shù)是否符合要求 10??????*?2)根據(jù)concurrencyLevel(16),計(jì)算Segment[]的容量ssize(16)與擴(kuò)容移位條件sshift(4) 11??????*?3)根據(jù)sshift與ssize計(jì)算將來用于定位到相應(yīng)Segment的參數(shù)segmentShift與segmentMask 12??????*?4)根據(jù)ssize創(chuàng)建Segment[]數(shù)組,容量為ssize(16) 13??????*?5)根據(jù)initialCapacity(16)與ssize計(jì)算用于計(jì)算HashEntry[]容量的參數(shù)c(1) 14??????*?6)根據(jù)c計(jì)算HashEntry[]的容量cap(1) 15??????*?7)根據(jù)cap與loadFactor(0.75)為每一個(gè)Segment[i]都實(shí)例化一個(gè)Segment 16??????*?8)每一個(gè)Segment的實(shí)例化都做下面這些事兒: 17??????*?8.1)為當(dāng)前的Segment初始化其loadFactor為傳入的loadFactor(0.75) 18??????*?8.2)創(chuàng)建一個(gè)HashEntry[],容量為傳入的cap(1) 19??????*?8.3)根據(jù)創(chuàng)建出來的HashEntry的容量(1)和初始化的loadFactor(0.75),計(jì)算擴(kuò)容因子threshold(0) 20??????*?8.4)初始化Segment的table為剛剛創(chuàng)建出來的HashEntry 21??????*/ 22?????public?ConcurrentHashMap(int?initialCapacity,float?loadFactor,int?concurrencyLevel)?{ 23?????????//?檢查參數(shù)情況 24?????????if?(loadFactor?<=?0f?||?initialCapacity?<?0?||?concurrencyLevel?<=?0) 25?????????????throw?new?IllegalArgumentException(); 26? 27?????????if?(concurrencyLevel?>?MAX_SEGMENTS) 28?????????????concurrencyLevel?=?MAX_SEGMENTS; 29? 30?????????/** 31??????????*?找一個(gè)能夠正好小于concurrencyLevel的數(shù)(這個(gè)數(shù)必須是2的幾次方的數(shù)) 32??????????*?eg.concurrencyLevel==16==>sshift==4,ssize==16 33??????????*?當(dāng)然,如果concurrencyLevel==15也是上邊這個(gè)結(jié)果 34??????????*/ 35?????????int?sshift?=?0; 36?????????int?ssize?=?1;//?segment數(shù)組的長度 37?????????while?(ssize?<?concurrencyLevel)?{ 38?????????????++sshift; 39?????????????ssize?<<=?1;//?ssize=ssize*2 40?????????} 41? 42?????????segmentShift?=?32?-?sshift;//?eg.segmentShift==32-4=28?用于根據(jù)給定的key的hash值定位到一個(gè)Segment 43?????????segmentMask?=?ssize?-?1;//?eg.segmentMask==16-1==15?用于根據(jù)給定的key的hash值定位到一個(gè)Segment 44?????????this.segments?=?Segment.newArray(ssize);//?構(gòu)造出了Segment[ssize]數(shù)組?eg.Segment[16] 45? 46?????????/* 47??????????*?下面將為segment數(shù)組中添加Segment元素 48??????????*/ 49?????????if?(initialCapacity?>?MAXIMUM_CAPACITY) 50?????????????initialCapacity?=?MAXIMUM_CAPACITY; 51?????????int?c?=?initialCapacity?/?ssize;//?eg.initialCapacity==16,c==16/16==1 52?????????if?(c?*?ssize?<?initialCapacity)//?eg.initialCapacity==17,c==17/16=1,這時(shí)1*16<17,所以c=c+1==2 53?????????????++c;//?為了少執(zhí)行這一句,最好將initialCapacity設(shè)置為2的幾次方 54?????????int?cap?=?1;//?每一個(gè)Segment中的HashEntry[]的初始化容量 55?????????while?(cap?<?c) 56?????????????cap?<<=?1;//?創(chuàng)建容量 57? 58?????????for?(int?i?=?0;?i?<?this.segments.length;?++i) 59?????????????//?這一塊this.segments.length就是ssize,為了不去計(jì)算這個(gè)值,可以直接改成i<ssize 60?????????????this.segments[i]?=?new?Segment<K,?V>(cap,?loadFactor); 61?????}注意:這個(gè)方法里邊我在頭部所寫的注釋非常重要,在這塊注釋寫明了:
每一個(gè)參數(shù)的作用
整個(gè)ConcurrentHashMap的一個(gè)創(chuàng)建步驟(以默認(rèn)的參數(shù)值為例)
免費(fèi)領(lǐng)取驗(yàn)證碼、內(nèi)容安全、短信發(fā)送、直播點(diǎn)播體驗(yàn)包及云服務(wù)器等套餐
更多網(wǎng)易技術(shù)、產(chǎn)品、運(yùn)營經(jīng)驗(yàn)分享請(qǐng)點(diǎn)擊。
相關(guān)文章:
【推薦】?十年?杭研技術(shù)秀 | “網(wǎng)易云存儲(chǔ)服務(wù)”從0到1發(fā)展之路
【推薦】?當(dāng)我們?cè)谡務(wù)搈ultidex65535時(shí),我們?cè)谡務(wù)撌裁?br />
轉(zhuǎn)載于:https://www.cnblogs.com/zyfd/p/10150816.html
總結(jié)
以上是生活随笔為你收集整理的CopyOnWriteArrayList源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue.js 三种方式安装--npm安装
- 下一篇: UVa 489 Hangman Judg