List底层结构

List的实现类常用的用

  • LinkedList
  • ArrayList
  • vector

LinkedList:线程不安全

底层结构是双向链表,开销在于需要存储结点信息以及结点指针信息。

List底层结构_第1张图片
双向链表是由三部分来组成的:prev、data、next

  • prev:存储上一个节点的地址
  • data:存储将要存储的数据
  • next:存储下一个节点的地址

List底层结构_第2张图片
双向链表的排序方式是没有顺序的;当我们新增一个元素时,只需要修改前一个元素的next和后一个元素的prev即可,删除元素同理;这样使得LinkedList对于新增和删除的效率大大提高。但是查询数据时,需要一个一个的查找,直到找到为止,使得查询的效率变得很低

get和set慢,add和remove更新快。

ArrayList:线程不安全

底层结构是可变数组,开销在于List列表预留一定空间。

数组存在的位置为在JVM的堆中,用来存储固定大小同类型元素的。当新的元素需要存储时,会存储在最前面,所以每次存储新元素时,所有的元素都会向后移动位置。同理,删除一个元素时,数组中所有的元素都会向前移动位置,所以ArrayList对于增删的效率很低。

数组里面的元素占用的内存相同并且连续排列的。在查询时可以根据数组的下标来进行快速访问,所以ArrayList对于查询效率高。

get和set快,add和remove更新慢。

扩容机制:

  1. 初始化容量10,初始最大容量Integer.MAX_VALUE - 8
  2. 先判断,加了新数据之后,原来的容量能不能放下
  3. 放不下的话,进入扩容方法
  4. 原容量*1.5(newCapacity = oldCapacity + (oldCapacity >> 1))
  5. 新容量与minCapacity比较,取较大的值,即扩容一次还不够,就按需取容量
  6. 如果新的容量超出了Integer.MAX_VALUE - 8,那就用Integer.MAX_VALUE

为什么Integer.MAX_VALUE - 8:

主要区别在于数组对象有一个额外的元数据,用于表示数组的大小。不只是数组的长度信息,还有数组对象的类信息还有同步信息

Vector:线程安全

大致与ArrayList保持一致,有以下几个区别

  • 每个方法上都加了synchronized的关键字来保证线程安全,效率降低
  • 扩容机制上,维护capacityIncrement增长系数,ArrayList是原容量*1.5,Vector采用newCapacity = oldCapacity + capacityIncrement > 0 ? capacityIncrement : oldCapacity。特就是说存在增长系数就直接加,没有的话就翻倍。

CopyOnWriteArrayList:线程安全

总体基于ArrayList,实现线程安全的方式:CopyOnWriteArrayList通过使用ReentrantLock锁来实现线程安全,写的时候获取副本进行修改,所以不影响读(读写分离)
区别在于:

  • 初始容量是0,每次扩容空间刚好够用,不会有多余的空间
  • 不能保证数据的实时一致性

Collections.SynchronizedList:线程安全

与Vector区别

  • 扩容机制不同,SynchronizedList与ArrayList一致
  • SynchronizedList锁代码块,并且可以选择锁的对象,Vector锁方法
  • SynchronizedList进行遍历的时候要手动加锁,Vector不用
  • SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类。:LinkedList直接转成 SynchronizedList但不能转变成Vector,因为底层结构限制

你可能感兴趣的:(认真搞数据结构,list,链表,数据结构)