并发类容器-第二讲
一、首先我们来熟悉一下跳表(数据结构和算法)
参考资料:
https://www.cnblogs.com/seniusen/p/9870398.html
https://blog.csdn.net/u010425776/article/details/54890215
跳表的由来:
作用:存储有序序列,并且实现高效的查找与插入删除。
存储有序序列最简单的办法就是使用数组,从而查找可以采用二分搜索,但插入删除需要移动元素较为低效。
因此出现了二叉搜索树,用来解决插入删除移动元素的问题。但二叉搜索树在最坏情况下会退化成一条单链表,搜索的效率降为O(n)。
为了避免二叉搜索树的退化,出现了二叉平衡树,它在每次插入删除节点后都会重新调整树形,使得它仍然保持平衡,从而保证了搜索效率,也保证了插入删除的效率。
此外,根据平衡算法的不同,二叉平衡树又分为:B+树、B-树、红黑树。
但平衡算法过于复杂,因此出现跳表。
二、ConcurrentSkipListMap 分析
参考文献:
https://www.cnblogs.com/skywang12345/p/3498556.html(比较详细)
简单总结:
ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景。
ConcurrentSkipListMap和TreeMap,它们虽然都是有序的哈希表。
但是,第一,它们的线程安全机制不同,TreeMap是非线程安全的,而ConcurrentSkipListMap是线程安全的。第二,ConcurrentSkipListMap是通过跳表实现的,而TreeMap是通过红黑树实现的。
关于跳表(Skip List),它是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的。
三、ConcurrentSkipListSet
参考文献:
https://www.cnblogs.com/duanxz/p/3549633.html(还算是比较详细)
简单总结:
ConcurrentSkipListSet是线程安全的有序的集合,适用于高并发的场景。
ConcurrentSkipListSet和TreeSet,它们虽然都是有序的集合。但是,第一,它们的线程安全机制不同,TreeSet是非线程安全的,而ConcurrentSkipListSet是线程安全的。第二,ConcurrentSkipListSet是通过ConcurrentSkipListMap实现的,而TreeSet是通过TreeMap实现的。
四、ConcurrentLinkedQueue
无界非阻塞队列,底层是个链表,遵循先进先出原则。
add,offer将元素插入到尾部,peek(拿头部的数据,但是不移除)和poll(拿头部的数据,但是移除)
五、写时复制容器 (CopyOnWriteArrayList、CopyOnWriteArraySet)
写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以写时复制容器也是一种读写分离的思想,读和写不同的容器。如果读的时候有多个线程正在向容器添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的,只能保证最终一致性。
适用读多写少的并发场景,常见应用:白名单/黑名单, 商品类目的访问和更新场景。
存在内存占用问题。