前言
作为一个经常使(mian)用(shi)的数据结构:跳表,我们对其应该不会感到陌生了,特别是java的跳表实现ConcurrentSkipListMap,某度查找下它的解读更是一抓一大把。但如果你看完这些文章就以为完全理解跳表的话,那可能在面试中被问得哑口无言:跳表插入节点时如何判断是否要增加层级?按概率的话具体概率是多少呢?为什么要这样设计呢?删除节点时为什么要先增加标记节点?源码中充斥着大量重复代码,为什么不作优化呢.....今天就给大家深入解读ConcurrentSkipListMap的核心原理。
建议观看文章前先了解以下内容:
通读ConcurrentSkipListMap源码并有一定了解
HM Linked List及其基于marker节点的优化方式
其它有序集合的数据结构
授之以渔
首先,解读一个数据结构或模式甚至服务,需要先了解它的作用是什么(解决的痛点),进而推测其比较容易理解的入口,最后带着问题去剖析其核心代码,即可快速入手,剩下就是边边角角的问题了。以跳表为例,它的作用是在高并发的场景下支持快速查找有序数据,自然可以推测其获取数据的方法get()最容易掌握。通过get()可以很快地了解其结构与性能提升的奥秘,最后带着如何建立起这种结构的问题去解读put与remove方法,基本上可以应付平时使(mian)用(shi)场景了。
put方法
这里只对部分问题与代码进行解读,首先我们来看put方法,在新增一个节点后如何判断是否需要增加层级?
// 以下是doPut关于level的部分
int rnd = ThreadLocalRandom.nextSecondarySeed();
if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
int level = 1, max;
while (((rnd