并发容器

ConcurrentSkipListMap和ConcurrentSkipListSet

ConcurrentSkipListMap和ConcurrentSkipListSet分别是TreeMap和TreeSet有序的容器的并发版本,内部加入了跳表

1,为什么选择跳表?
目前经常使用的平衡数据结构有:B树,红黑树,AVL树,SplayTree,Treep等,想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树出来吗?很难吧,这需要时间,要考虑很多细节,要参考一堆算法与数据结构之类的树,还要参考网上的代码,相当麻烦。
用跳表吧,跳表是一种随机化的数据结构,目前开源软件Redis和LevelDB(全文搜索引擎)都有用到它,它的效率和红黑树以及AVL树不相上下,但跳表的原理相当简单,时间复杂度非常趋近于红黑树。
跳表:
在这里插入图片描述

跳表(可以提高普通链表查询的速度,是扩展空间负责度):
	SkipList,以空间换时间,在原链表的基础上形成多层索引,当某个节点在插入时,随机决定这个节点是否成为上层索引,所以跳表又称为概率数据结构,这样有了索引之后,在查找的时候提高了效率。

	跳表的高度:
		n个元素的跳表,每个元素插入的时候都要做一次实验,用来决定元素占据的层数K,跳表的高度等于这n次实验中产生的最大k

	跳表具有如下性质:
		(1) 由很多层结构组成。
		(2) 每一层都是一个有序的链表。
		(3) 最底层(Level 1)的链表包含所有元素。
		(4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。
		(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

2,ConcurrentHashMap中为什么不使用跳表?
因为ConcurrentHashMap,因为用了分段锁,本身的空间利用率很低,如果再使用跳表用空间换取时间,就会使得ConcurrentHashMap的空间利用率更低,所以不使用跳表。

ConcurrentLinkedQueue

ConcurrentLinkedQueue是LinkedList的并发版本,无界非阻塞队列,底层是个链表,遵循先进先出FIFO原则。

其中的方法:
	add,offer:将元素插入到尾部
	peek:拿头部的数据,但是不移除
	poll:拿头部的数据,但是移除

写时复制容器

写时复制容器有两个,是CopeOnWriteArrayList和CopeOnWriteArraySet
写时复制的容器,通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以写时复制容器也是一种读写分离的思想,读和写不同的容器。如果读的时候有多个线程正在向容器添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的,只能保证最终一致性。
适用读多写少的并发场景,常见应用:白名单/黑名单,商品类目的访问和更新场景。
注意:存在内存占用问题。

和读写锁的区别?
写时复制容器是读写可以同时进行的,而读写锁是一个线程写的时候,其他线程不能读,是互斥的。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值