java常见集合用法与比较

本文深入对比分析了Java中各种集合类的特性和应用场景,包括ArrayList、LinkedList、Vector、CopyOnWriteArrayList、HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap、TreeMap、ConcurrentSkipListMap及其对应的Set实现。探讨了它们在性能、线程安全、内存消耗和数据一致性等方面的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,ArrayList vs LinkedList 区别

1,ArrayList的随机访问更高

2,LinkedList在头/尾节点执行插入/删除操作的效率比ArrayList要高

3,ArrayList每次扩容的容量是当前的1.5倍,LinkedList所占的内存空间要更小一些

4,ArrayList可以使用get(int)方式,LinkedList时应用iterator方式,否则效率会很低。

二,ArrayList vs Vector区别

1,二者都是基于数组实现的集合

2,vector是线程安全的,而ArrayList不是

3,由于Vector中的方法基本都是synchronized的,其性能低于ArrayList

4,Vector可以定义数组长度扩容的因子,ArrayList不能

三,ArrayList vs Vector vs CopyOnWriteArrayList区别

1,Vector与CopyOnWriteArrayList是ArrayList的线程安全版,基于数组实现的List

2,CopyOnWriteArrayList在写操作时会先复制出一个副本,在新副本上执行写操作,然后再修改引用,这种机制让 CopyOnWriteArrayList可以对读操作不加锁,这就使CopyOnWriteArrayList的读效率远高于Vector。

3,CopyOnWriteArrayList的理念比较类似读写分离,适合读多写少的多线程场景

4,CopyOnWriteArrayList只能保证数据的最终一致性,并不能保证数据的实时一致性,如果一个写操作正在进行中且并未完成,此时的读操作无法保证能读到这个写操作的结果

5,Vector是【绝对】线程安全的,CopyOnWriteArrayList只能保证读线程会读到【已完成】的写结果,但无法像Vector一样实现读操作的【等待写操作完成后再读最新值】的能力

6,CopyOnWriteArrayList读性能远高于Vector,并发线程越多优势越明显

7,CopyOnWriteArrayList占用更多的内存空间

四,HashMap

1,HashMap将Entry对象存储在一个数组中,并通过哈希表来实现对Entry的快速访问:

       由每个Entry中的key的哈希值决定该Entry在数组中的位置。以这种特性能够实现通过key快速查找到Entry,从而获得该key对应的value。在不发生哈希冲突的前提下,查找的时间复杂度是O(1)。

       如果两个不同的key计算出的index是一样的,就会发生两个不同的key都对应到数组中同一个位置的情况,也就是所谓的哈希冲突。HashMap处理哈 希冲突的方法是拉链法,也就是说数组中每个位置保存的实际是一个Entry链表,链表中每个Entry都拥有指向链表中后一个Entry的引用。在发生哈希冲突时,将冲突的Entry追加至链表的头部。当HashMap在寻址时发现某个key对应的数组index上有多个Entry,便会遍历该位置上的 Entry链表,直到找到目标的Entry。

       HashMap由于其快速寻址的特点,可以说是最经常被使用的Map实现类

五,Hashtable

       与HashMap几乎完全一样,都是通过数组存储Entry,以key的哈希值计算Entry在数组中的index,用拉链法解决哈希冲突。二者最大的不同在于,Hashtable是线程安全的,其提供的方法几乎都是同步的。

六,ConcurrentHashMap

1,ConcurrentHashMap是HashMap的线程安全版(自JDK1.5引入),提供比Hashtable更高效的并发性能。

2,Hashtable 在进行读写操作时会锁住整个Entry数组,这就导致数据越多性能越差。

3,ConcurrentHashMap使用分离锁的思路解决并发性能,其将 Entry数组拆分至Segment中,以哈希算法决定Entry应该存储在哪个Segment,这样就可以实现在写操作时只对一个Segment 加锁,大幅提升了并发写的性能。 

4,ConcurrentHashMap在绝大部分情况下都不需要加锁,其Entry中的value是volatile的,这保证了value被修改时的线程可见性,无需加锁便能实现线程安全的读操作。

5,ConcurrentHashMap的高性能是有代价的(否则Hashtable就没有存在价值了),那就是它不能保证读操作的绝对 一致性

6,ConcurrentHashMap保证读操作能获取到已存在Entry的value的最新值,同时也能保证读操作可获取到已完成的写操作的内容,但如果写操作是在创建一个新的Entry,那么在写操作没有完成时,读操作是有可能获取不到这个Entry的。

七,HashMap vs Hashtable vs ConcurrentHashMap

1,HashMap不是线程安全的,多线程环境下除了不能保证数据一致性之外,还有可能在rehash阶段引发Entry链表成环,导致死循环

2,Hashtable是线程安全的,能保证绝对的数据一致性,但性能是问题,并发线程越多,性能越差

3,ConcurrentHashMap 也是线程安全的,使用分离锁和volatile等方法极大地提升了读写性能,同时也能保证在绝大部分情况下的数据一致性。但其不能保证绝对的数据一致性, 在一个线程向Map中加入Entry的操作没有完全完成之前,其他线程有可能读不到新加入的Entry

八,LinkedHashMap

       LinkedHashMap与HashMap非常类似,唯一的不同在于前者的Entry在HashMap.Entry的基础上增加了到前一个插入和后一个插入的Entry的引用,以实现能够按Entry的插入顺序进行遍历。

九,TreeMap

1,TreeMap是基于红黑树实现的Map结构,其Entry类拥有到左/右叶子节点和父节点的引用,同时还记录了自己的颜色:红黑树实际是一种算法复杂但高效的平衡二叉树,具备二叉树的基本性质,即任何节点的值大于其左叶子节点,小于其右叶子节点,利用这种特性,TreeMap能够实现Entry的排序和快速查找。 
2,TreeMap的Entry是有序的,所以提供了一系列方便的功能,比如获取以升序或降序排列的KeySet(EntrySet)、获取在指定key(Entry)之前/之后的key(Entry)等等。适合需要对key进行有序操作的场景。

十,ConcurrentSkipListMap

1,ConcurrentSkipListMap同样能够提供有序的Entry排列,但其实现原理与TreeMap不同,是基于跳表(SkipList)的:

2,如上图所示,ConcurrentSkipListMap由一个多级链表实现,底层链上拥有所有元素,逐级上升的过程中每个链的元素数递减。在查找时从顶层链出发,按先右后下的优先级进行查找,从而实现快速寻址。

3, 与TreeMap不同,ConcurrentSkipListMap在进行插入、删除等操作时,只需要修改影响到的节点的右引用,而右引用又是volatile的,所以ConcurrentSkipListMap是线程安全的。但ConcurrentSkipListMap与ConcurrentHashMap一样,不能保证数据的绝对一致性,在某些情况下有可能无法读到正在被插入的数据。

十一,TreeMap vs ConcurrentSkipListMap

1,二者都能够提供有序的Entry集合
2,二者的性能相近,查找时间复杂度都是O(logN)
3,ConcurrentSkipListMap会占用更多的内存空间
4,ConcurrentSkipListMap是线程安全的,TreeMap不是

十二,Set类集合

1,Set 接口继承Collection,用于存储不含重复元素的集合。几乎所有的Set实现都是基于同类型Map的,简单地说,Set是阉割版的Map。

2,每一个Set内都有一个同类型的Map实例(CopyOnWriteArraySet除外,它内置的是CopyOnWriteArrayList实例),Set把元素作为key存储在自己的Map实例中,value则是一个空的Object。

3,Set的常用实现也包括 HashSet、TreeSet、ConcurrentSkipListSet等,原理和对应的Map实现完全一致

 

数据结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员雪球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值