Java里多个Map的性能比較(TreeMap、HashMap、ConcurrentSkipListMap)
问题
比較Java原生的
1. TreeMap
2. HashMap
3. ConcurrentSkipListMap
3种Map的效率。
结果
模拟150W以内海量数据的插入和查找,通过添加和查找双方面的性能測试,结果例如以下:
Map类型 | 插入 | 查找(在100W数据量中) | |||||
10W | 50W | 100W | 150W | 0-1W | 0-25W | 0-50W | |
ConcurrentSkipListMap | 62 ms | 227 ms | 433 ms | 689ms | 7 ms | 80 ms | 119 ms |
HashMap | 18 ms | 93 ms | 217 ms | 303ms | 2 ms | 13 ms | 45 ms |
TreeMap | 33 ms | 228 ms | 429 ms | 584 ms | 4ms | 34 ms | 61 ms |
分析说明
图1- 1常数和logn函数效率对照演示样例图(横轴-n数据量,纵轴-f(n)时间)
TreeMap基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(log n)。
HashMap是基于散列表实现的,时间复杂度平均能达到O(1)。
ConcurrentSkipListMap是基于跳表实现的,时间复杂度平均能达到O(log n)。
如图所看到的:
当数据量添加时,HashMap会引起散列冲突,解决冲突须要多花费一些时间代价,故在f(n)=1向上浮动。
随着数据量的添加,HashMap的时间花费小且稳定,在单线程的环境下比TreeMap和ConcurrentSkipListMap在插入和查找上有非常大的优势。
(1) TreeMap与HashMap相比較
Ø HashMap里面存入的键值对在取出的时候是随机的,它依据键的HashCode值存储数据,依据键能够直接获取它的值,具有非常快的訪问速度。在Map 中插入、删除和定位元素,HashMap是最好的选择。
Ø TreeMap取出来的是排序后的键值对。插入、删除须要维护平衡会牺牲一些效率。但假设要按自然顺序或自己定义顺序遍历键,那么TreeMap会更好。
本測试添加和查找功能,HashMap比TreeMap的效率要高。
(2) TreeMap与ConcurrentSkipListMap相比較
Ø Skip list(跳表)是一种能够取代平衡树的数据结构,默认是依照Key值升序的。Skip list让已排序的数据分布在多层链表中,以0-1随机数决定一个数据的向上攀升与否,通过“空间来换取时间”的一个算法,在每一个节点中添加了向前的指针,在插入、删除、查找时能够忽略一些不可能涉及到的结点,从而提高了效率。
从概率上保持数据结构的平衡比显示的保持数据结构平衡要简单的多。对于大多数应用,用Skip list要比用树算法相对简单。因为Skip list比較简单,实现起来会比較easy,尽管和平衡树有着同样的时间复杂度(O(logn)),可是skip list的常数项会相对小非常多。Skip list在空间上也比較节省。一个节点平均仅仅须要1.333个指针(甚至更少)。
图1-2 Skip list结构图(以7,14,21,32,37,71,85序列为例)
Skip list的性质
(1) 由非常多层结构组成,level是通过一定的概率随机产生的。
(2) 每一层都是一个有序的链表,默认是升序,也能够依据创建映射时所提供的Comparator
进行排序,详细取决于使用的构造方法。
(3) 最底层(Level 1)的链表包括全部元素。
(4) 假设一个元素出如今Level i 的链表中,则它在Level i 之下的链表也都会出现。
(5) 每一个节点包括两个指针,一个指向同一链表中的下一个元素,一个指向以下一层的元素。
Ø ConcurrentSkipListMap具有Skip list的性质 ,而且适用于大规模数据的并发訪问。多个线程能够安全地并发运行插入、移除、更新和訪问操作。与其它有锁机制的数据结构在巨大的压力下相比有优势。
Ø TreeMap插入数据时平衡树採用严格的旋转(比方平衡二叉树有左旋右旋)来保证平衡,因此Skip list比較easy实现,并且相比平衡树有着较高的执行效率。
本測试的添加功能,ConcurrentSkipListMap和TreeMap效率相差不大。
查找功能在50W数据量以后,TreeMap更有效率,由于ConcurrentSkipListMap自带锁机制,会占用一些效率,但对于多线程并发的环境下,ConcurrentSkipListMap的效率会比Treep要好的。
本測试查找方法使用的时候map的get方法。对于ConcurrentSkipListMap,获得顺序片段,可用subMap()方法,提取50w的子序列仅仅须要1ms,具有巨大优势。 ConcurrentSkipListMap的效率比HashMap和TreeMap效率都要高。