Java常用併發容器總結(四)
阿新 • • 發佈:2019-02-01
ConcurrentSkipListMap
1.介紹
跳錶是一種可以用來快速查詢的資料結構,類似於平衡樹,他們都可以對元素進行快速的查詢。但一個重要的區別是:對平衡樹的插入往往可能導致平衡樹進行一次全域性的調整;而對跳錶的插入和刪除之需要的區域性資料操作即可。這樣的好處是,在高併發環境下,對平衡樹的操作需要一個全域性鎖來保證執行緒安全,但是對於跳錶則只需要部分鎖,這樣會擁有更好地效能。
就查詢的效能而言,跳錶的時間複雜度也是O(logN)。因此,在併發的資料結構中,JDK使用跳錶實現一個Map。
跳錶的本質是分層的多個連結串列,最上層的元素最少,查詢操作從最上層開始進行。
使用跳錶實現Map和使用Hash演算法實現Map的另一個不同之處在於,HashMap並不會維護元素的順序,而跳錶內的所有元素都是排序的,在對跳錶遍歷時會得到一個有序的結果
2.程式碼分析
ConcurrentSkipListMap是使用跳錶實現的併發安全的Map結構,其內部由幾個關鍵的資料結構組成。首先是Node。一個Node表示跳錶的某一層的一個節點。
//一個Node表示跳錶的一個節點
static final class Node<K,V> {
//該節點的key
final K key;
//該節點的value
volatile Object value;
//資料域,指向同一層的後繼節點
volatile Node<K,V> next;
Node(K key, Object value, Node<K,V> next) {
this.key = key;
this.value = value;
this.next = next;
}
另一個重要的資料結構是Index,它內部包裝了Node,同時增加了向下的引用和向右的引用:
static class Index<K,V> {
//內部封裝了一個Node
final Node<K,V> node;
//資料域,指向下一層的節點
final Index<K,V> down;
//資料域,指向同一層的右邊的節點
volatile Index<K,V> right;
Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
this.node = node;
this.down = down;
this.right = right;
}
此外,還有一個HeadIndex的資料結構,表示連結串列頭部的第一個Index,並記錄當前在第幾層:
//HeadIndex表示第level層的表頭Index
static final class HeadIndex<K,V> extends Index<K,V> {
//表示當前在第幾層
final int level;
HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
super(node, down, right);
this.level = level;
}
}
對於跳錶的所有操作,就是組織好這些Index之間的連線關係。
3.適用場景
如果想在高併發環境下,使用一個有序的Map,那麼ConcurrentSkipListMap將是不二的選擇。