并发容器及安全共享策略总结

并发容器及安全共享策略总结

在这里插入图片描述
J.U.C指的java.util.concurrent包

并发容器 - CopyOnWriteArrayList

CopyOnWriteArrayList 相比ArrayList 是线程安全的,根据名称知道:写操作时复制;
写操作时拷贝一份,在新的数组上进行写操作,操作完之后,再将原来的数组指向新的数组。
(CopyOnWriteArrayList整个add操作都是在的锁保护下进行,这么做主要避免在多线程并发做add操作时,复制出多个数组,把数据搞乱了,导致最终的数组数据不是我们期望的)
在这里插入图片描述
get没有加锁,直接取
在这里插入图片描述

CopyOnWriteArrayList缺点
1、写操作时需要拷贝数组,消耗内存,数据比较多时,会导致YangGC或者FullGC
2、不能用于实时读的场景,拷贝数组和新增元素都需要时间。比如调用set操作后读取的数据可能还是旧的,虽然能做到最终的一致性,但是不能满足实时性。
因此,CopyOnWriteArrayList适合读多写少的场景

注意:如果无法保证CopyOnWriteArrayList里面放多少数据,也不知道add,set多少次操作,要慎用CopyOnWriteArrayList,
因为如果数组更新太多,每次更新操作时都要复制,代价太高,在高性能的互联网应用中,这种操作可能会分分钟引起故障。
绝大部分,如果CopyOnWriteArrayList 数组数据少,完全可以用CopyOnWriteArrayList 代替ArrayList

CopyOnWriteArrayList设计思想
1.读写分离;
2.最终一致性;
3.使用时另外开辟空间,解决并发冲突。

在这里插入图片描述

并发容器 - CopyOnWriteArraySet

HashSet对应CopyOnWriteArraySet,CopyOnWriteArraySet是线程安全的,他的底层实现是CopyOnWriteArrayList,因此适合于大小很小的set集合,只读操作远大于可变操作,因为要复制整个数组操作,所有add,remove,set等操作开销比较大,迭代器不支持可变的remove操作,CopyOnWriteArraySet 使用迭代器遍历时速度很快,而且不会与其他线程发生冲突。
在这里插入图片描述

在这里插入图片描述
执行结果:5000

并发容器 - ConcurrentSkipListSet

TreeSet 对应ConcurrentSkipListSet,ConcurrentSkipListSet是jdk6新增的类,和TreeSet一样是支持自然排序的,和其他set一样,ConcurrentSkipListSet是基于map集合的,底层是ConcurrentSkipListSet实现的,在多线程环境下,ConcurrentSkipListSet里面的add,get,remove,都是线程安全的,多个线程可以安全的执行插入,移除,访问操作,但是对于批量操作,比如addAll, removeAll,ContainsAll(),并不能保证以原子方式执行,理由很简单,因为add本身是原子操作,但是当批量操作时,就不能保证原子性了,所以addAll, removeAll,ContainsAll(),批量操作时,需要自己手动加同步操作, 比如加锁,保证同一时间内,只能有一个线程操作,ConcurrentSkipListSet 不允许加入null。

在这里插入图片描述
执行结果:5000

ConcurrentHashMap

HashMap对应线程安全的并发容器是ConcurrentHashMap,ConcurrentHashMap不允许null值,在实际的操作中,ConcurrentHashMap除了少量的插入操作和删除操作外,绝大部分都是读取操作,针对读操作,ConcurrentHashMap做了大量优化 ,因此这个类有特别好的并发性,在高并发下有特别好的表现,也如此,这个类经常在面试中用到,后面章节会有专门介绍ConcurrentHashMap 的实现原理。
在这里插入图片描述
运行结果:5000

ConcurrentSkipListMap

ConcurrentSkipListMap是TreeMap ,内部是SkipList跳表结构实现的,有人曾拿ConcurrentSkipListMap和ConcurrentHashMap,在4个线程,1.6万数据量下,ConcurrentHashMap的存取速度是ConcurrentSkipListMap的4倍左右,但是ConcurrentSkipListMap也有几个ConcurrentHashMap无法比拟的优点:
1、ConcurrentSkipListMap 的key 是有序的,这个ConcurrentHashMap是做不到的;
2、ConcurrentSkipListMap支持更高的并发,ConcurrentSkipListMap的存取时间几乎和线程数是没有关系的,也就是在数据量一定的情况下,并发数越多,ConcurrentSkipListMap越能体现出它的优势,在非并发情况下,经常使用TreeMap;

此外对于并发性相对较低的并行程序,我们也可以使用Collections里面的类,synchronizedSortedMap ,synchronizedSortedMap是将SortedMap进行包装,也可以提供较好的效率。

对于高并发的环境中,应该使用ConcurrentSkipListMap 提供更高的并发读,如果再高并发环境中要对键值对排序时,优先选择ConcurrentSkipListMap,可以提供更好的并发度
在这里插入图片描述

执行结果:5000

总结

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这四个策略只要是从,不可变对象,线程封闭,同步容器,并发容器总结出来的

猜你喜欢

转载自blog.csdn.net/wangnanwlw/article/details/86505126