Java常用并发容器总结(四)

来源:互联网 发布:手机装潢设计软件 编辑:程序博客网 时间:2024/04/29 17:13

ConcurrentSkipListMap

1.介绍

跳表是一种可以用来快速查找的数据结构,类似于平衡树,他们都可以对元素进行快速的查找。但一个重要的区别是:对平衡树的插入往往可能导致平衡树进行一次全局的调整;而对跳表的插入和删除之需要的局部数据操作即可。这样的好处是,在高并发环境下,对平衡树的操作需要一个全局锁来保证线程安全,但是对于跳表则只需要部分锁,这样会拥有更好地性能。
就查询的性能而言,跳表的时间复杂度也是O(logN)。因此,在并发的数据结构中,JDK使用跳表实现一个Map。
跳表的本质是分层的多个链表,最上层的元素最少,查找操作从最上层开始进行。
使用跳表实现Map和使用Hash算法实现Map的另一个不同之处在于,HashMap并不会维护元素的顺序,而跳表内的所有元素都是排序的,在对跳表遍历时会得到一个有序的结果。因此,如果需要一个有序的并发安全的Map,使用跳表是不二的选择。

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将是不二的选择。

1 0
原创粉丝点击