ArrayList

1.1. Arraylist 和 Vector 的区别?

1、ArrayList 是 List 的主要实现类,底层使用 Object[ ]存储,适用于频繁的查找工作,线程不安全 ;
2、Vector 是 List 的古老实现类,底层使用 Object[ ]存储,线程安全的。

1.2. Arraylist 与 LinkedList 区别?

1、是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
2、底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
3、插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度近似为o(n))因为需要先移动到指定位置再插入。
4、是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
5、内存空间占用: ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

1.3.ArrayList和LinkedList线程不安全该怎么解决?

线程安全解决方法:

方法1:Collections.synchronizedList(new LinkedList)

SynchronizedList是Collections的内部类,Collections提供了synchronizedList方法,可以将一个

线程不安全的List包装成线程安全的List,即SynchronizedList。它比Vector有更好的扩展性和兼

容性,但是它所有的方法都带有同步锁,也不是性能最优的List。

方法2:将ArrayList和LinkedList换成线程安全的集合

CopyOnWriteArrayList、ConcurrentLinkedQueue

CopyOnWriteArrayList是Java 1.5在java.util.concurrent包下增加的类,它采用复制底层数组的方
式来实现写操作
当线程对此类集合执行读取操作时,线程将会直接读取原集合本身,无须加锁与阻
塞。当线程对此类集合执行写入操作时,集合会在底层复制一份新的数组,接下来对新的数组执行
写入操作
。由于对集合的写入操作都是对数组的副本执行操作,因此它是线程安全的。在所有线程

安全的List中,它是性能最优的方案

谈谈CopyOnWriteArrayList的原理

CopyOnWriteArrayList是Java并发包里提供的并发类,简单来说它就是一个线程安全且读操作无锁的ArrayList。正如其名字一样,在写操作时会复制一份新的List,在新的List上完成写操作,然后再将原引用指向新的List。这样就保证了写操作的线程安全。CopyOnWriteArrayList允许线程并发访问读操作,这个时候是没有加锁限制的,性能较高。而写操作的时候,则首先将容器复制一份,然后在新的副本上执行写操作,这个时候写操作是上锁的。结束之后再将原容器的引用指向新容器。注意,在上锁执行写操作的过程中,如果有需要读操作,会作用在原容器上。因此上锁的写操作不会影响到并发访问的读操作。

优点:读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。在遍历传统的List时,若中途有别的线程对其进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其"读写分离"的思想,遍历和修改操作分别作用在不同的List容器,所 以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了。

缺点:一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC。二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性。而CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。

方法3:使用Vector

Vector内部方法主要使用synchronized关键字

1.4.ArrayList的扩容机制

1.ArrayList以无参构造方法创建ArrayList时,初始化赋值的是一个空数组,当真正对数组进行添加元素操作时,才真正分配容量。当向ArrayList中添加第一个元素时,数组容量默认扩容为10。
2、当再使用add 方法添加新元素时,首先调用ensureCapacityInternal(size + 1)方法,得到最小扩容量。
3、将最小扩容量放入ensureExplicitCapacity(minCapacity)方法,将最小扩容量与当前数组长度进行比较,判断是否需要扩容。

4.当需要扩容时,ArrayList每次扩容都以旧数组容量的1.5倍进行扩容

5.然后再判断新容量是否大于最小扩容量,如果还是小于最小扩容量,那就把最小扩容量当作数组的新容量

6.如果新的容量已经大于最大容量MAX_ARRAY_SIZE(MAX_ARRAY_SIZE,MAX_ARRAY_SIZE为Integer.MAX_VALUE-8,-8是为了避免无穷),则会调用hugeCapacity()方法,返回Integer的最大值。

7.再通过Arrays.copyOf()方法将原数组中的内容放到扩容后的新数组里面。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值