几种集合的区别及适用场景与哪些集合类是线程安全的?哪些不安全?

后台开发工作中经常遇到一些使用集合的场景,几种集合的优缺点又老是记不住,所以写了这篇博客。

首先大的集合分为:List,Set,Map三种,其中List与Set是继承自Collection,而Map不是。

List与Set的区别:List中的元素有存放顺序,并且可以存放重复元素,检索效率高,插入删除效率低,Set没有存放顺序,而且不可以存放重复元素,后来的元素会把前面重复的元素替换掉,检索效率低,插入删除效率高。(Set存储位置是由它的HashCode码决定的,所以它存储的对象必须有equals()方法,而且Set遍历只能用迭代,因为它没有下标。)

1、最常用的集合:ArrayList

本人比较懒,最常用的就是最简单的集合,因为用起来感觉比较方便。

特点:ArrayList集合中元素存储的位置是连续的,所以查询起来会比较快捷,但是执行插入删除操作会比较麻烦一点,会引起其他元素位置的变化。

注意:list中存储的是对象的引用,而不是对象本身。如果不清楚这一点会在这里有个坑,例如:

有人为了节省优化代码,节省虚拟机内存会这么写代码:

List<List<String>> list=new ArrayList<>();

List<String> list2=new ArrayList<>();

for(int i=0;i<10;i++){

    list2.add(""+i);    

    list.add(list2);

    list2.clear();

}

这样写虽然可以一个对象重复使用,但是,list存储的是对象的引用,当list2.clear();的时候,list中的list2也会clear,这样最后得到的就只能是一堆空的集合了。

2、与最常用集合相反的集合:LinkedList

LinkedList与ArrayList是互补的,所以ArrayList的优点就是LinkedList的缺点,ArrayList的缺点就是LinkedList的优点。

特点:LinkedList中元素位置是任意的,所以执行插入删除操作效率较高,查询效率较低。

3、与一般集合都相反的集合:Vector

为什么说它与一般集合都相反呢?因为它是一种老的动态数组,很多方法都用synchonized修饰,所以它是线程安全得,而一般集合是线程不安全得。

特点:多个线程同时访问不会发生不确定的结果,但是它的效率会比较低,如果要考虑线程安全的话可以用它。

4、Set中最常用的集合:HashSet

在用Set集合的时候我几乎用的都是HashSet,HashSet是使用Hash表实现的,集合里面的元素是无序得,可以有null值,但是不能有重复元素。

特点:因为相同的元素具有相同的hashCode,所以不能有重复元素

5、Set中第二常用的集合:TreeSet

TreeSet是用二叉树结构实现的集合

特点:集合中的元素是有顺序得,不允许放入null,同样不能放入重复元素。

6、第二常用的集合:HashMap

经常遇到需要使用键值对存储的场景,而HashMap是用得最多的一种键值对存储的集合。

特点:HashMap允许空键值,并且它是非线程安全的,所以插入、删除和定位元素会比较快。

7、一些不太常用的Map集合:TreeMap,HashTable

TreeMap是基于红黑树实现的,适用于按自然顺序火兹定于顺序遍历key。

HashTable是基于HashCode实现的,但它是线程安全的,所以会比HashMap效率低,而且不允许null值。

线性安全的
Vector:只要是关键性的操作,方法前面都加了synchronized关键字,来保证线程的安全性
Hashtable:使用了synchronized关键字,所以相较于Hashmap是线程安全的。
ConcurrentHashMap:使用锁分段技术确保线性安全,是一种高效但是线程安全的集合。
Stack:栈,也是线程安全的,继承于Vector。

线性不安全的
Hashmap
Arraylist
LinkedList
HashSet
TreeSet
TreeMap

Hashmap:HashMap在put操作的时候,如果插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是resize,这个会重新将原数组的内容重新hash到新的扩容数组中,在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。

Arraylist: List 对象在做 add 时,执行 Arrays.copyOf 的时候,返回一个新的数组对象。当有线程 A、B… 同时进入 grow方法,多个线程都会执行 Arrays.copyOf 方法,返回多个不同的 elementData 对象,假如,A先返回,B 后返回,那么 List.elementData ==A. elementData,如果同时B也返回,那么 List.elementData ==B. elementData,所以线程B就把线程A的数据给覆盖了,导致线程A的数据被丢失。

LinkedList:与Arraylist线程安全问题相似,线程安全问题是由多个线程同时写或同时读写同一个资源造成的。

HashSet:底层数据存储结构采用了Hashmap,所以Hashmap会产生的线程安全问题HashSet也会产生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值