ConcurrentSkipListMap内部是一种新的数据结构可以叫它是跳跃链表结构,其节点相当于是excel中的表格用了存储空间换取操作时间的,其查询时间复杂度是log(n)另外插入时已做好节点的排序,遍历的时候就是排好序的了
ConcurrentSkipListMap是可以并发操作的map,其key和value不能为null其插入操作会比较耗性能,可以用在并发环境插入少查询多的场景。
下媔是它的结构示意图:
从下面代码中看到链表中新增加了一个Index对象,用来封装Node对象其向下向右指向其他Index对象,构建起了跳跃链表另外其实现了ConcurrentNavigableMap接口,这里不对这个导航maq做介绍了还有Maq接口是没有继承Iterable接口,所有也不用实现迭代器方法
put方法的实现在doPut方法里面,分3块代碼构建纵向的index可以理解是构建上图中值为119这个节点,下面结合代码分析
如果把以上put方法理解了,我们再来学习get方法就容易多了简单來说get方法就是找到前驱节点,然后对比前驱的后继节点的key与给定的key是否一致
从以下代码可以看到size方法没有加锁,它是从节点的第一个元素遍历统计value不为null的节点数。所以该方法不是原子安全的
判断map是否为空直接检查第一个节点是否为null即可
从下面方法中可以看到,clear没有加鎖不是原子性的。
- 以存储空间换取查询和排序的时间是一种便宜的查找和排序算法。
- CAS自旋实现插入操作
- size方法,判断方法遍历方法等不是原子安全的。
- 在并发环境少插入,多查找并希望遍历有序的场景下可考虑使用。
PriorityQueue 名叫优先级队列底层由堆结构實现,默认是小根堆通过 offer 方法添加进去的元素会进行堆排序,最小的元素放在堆顶通过 peek 方法可以获得堆顶(最小)元素。通过 poll 方法可鉯删除堆顶元素同时获得堆顶元素删除之后剩下的元素中最小的元素仍处于堆顶。
某电商平台入驻了大量的商家商家可以在平台销售商品,用户可以在平台的商家那里购买商品用户付款后如果对购买到的商品不满意,可以向平台发起投诉用户对某商家的某件商品的投诉记录会存储在一张表中,表结构如下:
现在的需求是:找到投诉记录最多的前 3 个商家目的是在搜索时对其店铺进行降权处理。
- 创建┅个小根堆(PriorityQueue 默认就是小根堆)
- 小根堆中元素的数量小于 3 的时候就直接向集合中添加元素
- 当堆中的元素个数等于 3 的时候通过 peek 方法取出堆頂元素(最小的那个)与当前遍历到的元素比较
- 如果当前遍历到的元素大于堆顶元素,就把原堆顶元素移除把当前元素加入堆中
- 这样使嘚移除的元素都小于堆中的元素
- 所以最后堆中保留下来的就是最大的N个元素
可以看出最终的结果是 101,102,104 这三家店的投诉次数最多,符合预期
PriorityQueue 主要在大数据量求 TopN 这种场景下使用的,少量数据直接排个序就 ok
关注我的微信公众号(曲健磊的个人随笔),获取更多精彩内容: