ArrayList、LinkedList与Vector的区别
区别
特性 | ArrayList | LinkedList | Vector |
---|---|---|---|
线程安全性 | 非线程安全 | 线程安全 | 线程安全 |
底层实现 | 数组 | 双向链表 | 数组 |
动态扩容 | 支持 | 不支持 | 支持 |
访问元素速度 | 快 | 慢 | 相对较慢 |
插入/删除速度 | 慢 | 快 | 相对较慢 |
接口实现 | List | List, Deque | List |
允许存放重复元素 | 是 | 是 | 默认不允许 |
扩容大小 | 当前容量的一半 | 无扩容概念 | 当前容量的一半 |
访问元素方式 | 索引 | 遍历链表 | 索引 |
ArrayList是如何扩容的
首先,我们要明白ArrayList是基于数组的,我们都知道,申请数组的时候,只能申请一个定长的数组,那么List是如何通过数组扩容的呢?ArrayList的扩容分为以下几步:
- 检查新增元素后是否会超过数组的容量,如果超过,则进行下一步扩容
- 设置新的容量为老容量的1.5倍,最多不超过2^31-1 (Java 8中ArrayList的容量最大是Integer.MAX_VALUE - 8,即2^31-9。这是由于在Java 8中,ArrayList内部实现进行了一些改进,使用了一些数组复制的技巧来提高性能和内存利用率,而这些技巧需要额外的8个元素的空间来进行优化。)
- 之后,申请一个容量为1.5倍的数组,并将老数组的元素复制到新数组中,扩容完成
为什么ArrayList非线程安全
- 非原子性操作:ArrayList的增加、删除和修改操作并不是原子性的,它们可能需要多个步骤来完成。在多线程环境下,如果两个线程同时对ArrayList进行修改操作,可能会导致其中一个线程的修改结果被覆盖或丢失。
- 不支持并发修改:当一个线程在遍历ArrayList的同时,另一个线程对ArrayList进行修改操作,可能会导致遍历操作抛出ConcurrentModificationException异常。
- 缺乏同步机制:ArrayList没有内置的同步机制来保证多线程操作的安全性。因此,在多线程环境下,需要使用额外的同步手段(如synchronized关键字或并发集合类)来保证ArrayList的线程安全性。