一,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实现完全一致
数据结构