ConcurrentSkipListMap深入分析
1.前言
ConcurrentHashMap與ConcurrentSkipListMap性能測(cè)試
在4線程1.6萬(wàn)數(shù)據(jù)的條件下,ConcurrentHashMap 存取速度是ConcurrentSkipListMap 的4倍左右。但ConcurrentSkipListMap有幾個(gè)ConcurrentHashMap 不能比擬的優(yōu)點(diǎn):
-
ConcurrentSkipListMap 的key是有序的。
-
ConcurrentSkipListMap 支持更高的并發(fā)。ConcurrentSkipListMap 的存取時(shí)間是log(N),和線程數(shù)幾乎無(wú)關(guān)。也就是說(shuō)在數(shù)據(jù)量一定的情況下,并發(fā)的線程越多,ConcurrentSkipListMap越能體現(xiàn)出他 的優(yōu)勢(shì)
2.使用建議
在非多線程的情況下,應(yīng)當(dāng)盡量使用TreeMap。此外對(duì)于并發(fā)性相對(duì)較低的并行程序可以使用 Collections.synchronizedSortedMap將TreeMap進(jìn)行包裝,也可以提供較好的效率。對(duì)于高并發(fā)程序,應(yīng)當(dāng)使用 ConcurrentSkipListMap,能夠提供更高的并發(fā)度。
所以在多線程程序中,如果需要對(duì)Map的鍵值進(jìn)行排序時(shí),請(qǐng)盡量使用ConcurrentSkipListMap,可能得到更好的并發(fā)度。
注意,調(diào)用ConcurrentSkipListMap的size時(shí),由于多個(gè)線程可以同時(shí)對(duì)映射表進(jìn)行操作,所以映射表需要遍歷整個(gè)鏈表才能返回元素個(gè)數(shù),這個(gè)操作是個(gè)O(log(n))的操作。
?3.什么是SkipList
Skiplist(跳表)是一種可以代替平衡樹(shù)的數(shù)據(jù)結(jié)構(gòu),默認(rèn)是按照Key值升序的。Skiplist讓已排序的數(shù)據(jù)分布在多層鏈表中,以0-1隨機(jī)數(shù)決定一個(gè)數(shù)據(jù)的向上攀升與否,通過(guò)“空間來(lái)?yè)Q取時(shí)間”的一個(gè)算法,在每個(gè)節(jié)點(diǎn)中增加了向前的指針,在插入、刪除、查找時(shí)可以忽略一些不可能涉及到的結(jié)點(diǎn),從而提高了效率。
從概率上保持?jǐn)?shù)據(jù)結(jié)構(gòu)的平衡比顯示的保持?jǐn)?shù)據(jù)結(jié)構(gòu)平衡要簡(jiǎn)單的多。對(duì)于大多數(shù)應(yīng)用,用Skip list要比用樹(shù)算法相對(duì)簡(jiǎn)單。由于Skip list比較簡(jiǎn)單,實(shí)現(xiàn)起來(lái)會(huì)比較容易,雖然和平衡樹(shù)有著相同的時(shí)間復(fù)雜度(O(logn)),但是skip list的常數(shù)項(xiàng)會(huì)相對(duì)小很多。Skiplist在空間上也比較節(jié)省。一個(gè)節(jié)點(diǎn)平均只需要1.333個(gè)指針(甚至更少)。
? ? ? ? ? ? ? ??
圖1-1 Skip list結(jié)構(gòu)圖(以7,14,21,32,37,71,85序列為例)
Skip list的性質(zhì)
(1) 由很多層結(jié)構(gòu)組成,level是通過(guò)一定的概率隨機(jī)產(chǎn)生的。
(2) 每一層都是一個(gè)有序的鏈表,默認(rèn)是升序,也可以根據(jù)創(chuàng)建映射時(shí)所提供的Comparator進(jìn)行排序,具體取決于使用的構(gòu)造方法。
(3) 最底層(Level 1)的鏈表包含所有元素。
(4) 如果一個(gè)元素出現(xiàn)在Level i 的鏈表中,則它在Level i 之下的鏈表也都會(huì)出現(xiàn)。
(5) 每個(gè)節(jié)點(diǎn)包含兩個(gè)指針,一個(gè)指向同一鏈表中的下一個(gè)元素,一個(gè)指向下面一層的元素。
三、什么是ConcurrentSkipListMap
?
ConcurrentSkipListMap提供了一種線程安全的并發(fā)訪問(wèn)的排序映射表。內(nèi)部是SkipList(跳表)結(jié)構(gòu)實(shí)現(xiàn),在理論上能夠在O(log(n))時(shí)間內(nèi)完成查找、插入、刪除操作。
???? ? 注意,調(diào)用ConcurrentSkipListMap的size時(shí),由于多個(gè)線程可以同時(shí)對(duì)映射表進(jìn)行操作,所以映射表需要遍歷整個(gè)鏈表才能返回元素個(gè)數(shù),這個(gè)操作是個(gè)O(log(n))的操作。
?ConcurrentSkipListMap存儲(chǔ)結(jié)構(gòu)
ConcurrentSkipListMap存儲(chǔ)結(jié)構(gòu)圖
?
跳躍表(SkipList):(如上圖所示)
1.多條鏈構(gòu)成,是關(guān)鍵字升序排列的數(shù)據(jù)結(jié)構(gòu);
2.包含多個(gè)級(jí)別,一個(gè)head引用指向最高的級(jí)別,最低(底部)的級(jí)別,包含所有的key;
3.每一個(gè)級(jí)別都是其更低級(jí)別的子集,并且是有序的;
4.如果關(guān)鍵字 key在 級(jí)別level=i中出現(xiàn),則,level<=i的鏈表中都會(huì)包含該關(guān)鍵字key;
------------------------
ConcurrentSkipListMap主要用到了Node和Index兩種節(jié)點(diǎn)的存儲(chǔ)方式,通過(guò)volatile關(guān)鍵字實(shí)現(xiàn)了并發(fā)的操作
??
[java]?view plaincopy?
?
------------------------
ConcurrentSkipListMap的查找
通過(guò)SkipList的方式進(jìn)行查找操作:(下圖以“查找91”進(jìn)行說(shuō)明:)
?
紅色虛線,表示查找的路徑,藍(lán)色向右箭頭表示right引用;黑色向下箭頭表示down引用;
?
/get方法,通過(guò)doGet操作實(shí)現(xiàn)
?
[java]?view plaincopy?
?
?
------------------------------------------------
ConcurrentSkipListMap的刪除
通過(guò)SkipList的方式進(jìn)行刪除操作:(下圖以“刪除23”進(jìn)行說(shuō)明:)
?
紅色虛線,表示查找的路徑,藍(lán)色向右箭頭表示right引用;黑色向下箭頭表示down引用;
?
?
[java]?view plaincopy
?
-------------------------------------
?
ConcurrentSkipListMap的插入
?
?
通過(guò)SkipList的方式進(jìn)行插入操作:(下圖以“添加55”的兩種情況,進(jìn)行說(shuō)明:)
在level=2(該level存在)的情況下添加55的圖示:只需在level<=2的合適位置插入55即可
--------
在level=4(該level不存在,圖示level4是新建的)的情況下添加55的情況:首先新建level4,然后在level<=4的合適位置插入55
-----------
?
[java]?view plaincopy轉(zhuǎn)載于:https://www.cnblogs.com/wxgblogs/p/5465218.html
總結(jié)
以上是生活随笔為你收集整理的ConcurrentSkipListMap深入分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android被逼学习例子2
- 下一篇: java 中对对象的调用