List常见知识点
# List常见知识点
# 常见的List实现类
实现类 | 线程安全 | 效率 | 底层实现 |
---|---|---|---|
Vector | 安全 | 效率低 | 数组 |
ArrayList | 不安全 | 查找效率高,插入删除效率低 | 数组 |
LinkedList | 不安全 | 查找效率低,插入删除效率低 | 链表 |
CopyOnWriteArrayList | 安全 | 性能优于Vector,读不加锁,写加锁 | 数组 |
# ArrayList和Vector的区别
- ArrayList 是 List 的主要实现类,底层使用
Object[]
存储,适合于频繁的查找工作,线程不安全,效率高。 - Vector 是 List 的古老实现类,底层使用
Object[]
存储,线程安全,效率低。
# ArrayList和LinkedList区别
- 线程安全:都是线程不安全的。
- 底层数据结构:ArrayList 使用的是 Object 数组;LinkedList 使用的是双向链表
- 插入和删除:ArrayList 插入和删除慢,LinkedList插入和删除快。
- 随机访问:ArrayList 支持随机访问,LInkedList不支持
- 内存占用:LinkedList 占用空间多余 ArrayList
# Vector和CopyOnWriteArrayList区别
- 都是线程安全的,底层实现都是数组。
- Vector 的每个方法都进行了加锁。
- CopyOnWriteArrayList 的读操作不加锁,性能优于 Vector。
- CopyOnWriteArrayList 的写操作:加锁、复制数组、添加元素到复制数组、指向新数组、解锁
写时复制技术
CopyOnWrite(COW),写时复制技术,当大家共同去访问一个资源时,如果有人想要去修改这个资源的时候,就需要复制一个副本,去修改这个副本,而对于其他人来说访问得资源还是原来的,不会发生变化。
# ArrayList的并发异常
⌨ 运行以下代码
场景1: 使用 forEach 遍历时添加新元素
public class ArrayListForModifyTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 创建30个线程向list种添加元素
for (int i = 0; i < 30; i++) {
list.add(UUID.randomUUID().toString().substring(0, 8));
}
list.forEach(e -> {
System.out.println(e);
list.add(UUID.randomUUID().toString().substring(0, 8));
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
场景2: 多线程添加元素
public class ArrayListJucTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 创建30个线程向list种添加元素
for (int i = 0; i < 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
🗑 出现异常:并发修改异常
java.util.ConcurrentModificationException
1
📣 导致原因
快速失败(fail-fast)
🏷 解决方案(针对于场景1)
1 使用 Vector(远古实现类,不推荐)
List<String> list = new Vector<>();
1
2 使用线程安全工具类
List<String> list = Collections.synchronizedList(new ArrayList<>());
1
3 使用 CopyOnWriteArrayList (写时复制技术)
List<String> list = new CopyOnWriteArrayList<>();
1
# 快速失败(fail-fast)
是 Java 集合的一种错误检测机制。在使用迭代器对集合进行遍历的时候,在多线程操作下,集合可能会触发 fail-fast 机制,导致抛出 ConcurrentModificationException 异常;在单线程下,如果在遍历过程中对集合对象的内容进行修改的话也会触发 fail-fast 机制。
因为当迭代器使用 hashNext()
或 next()
遍历下一个元素之前,都会检测 modCount 变量是否为 expectedModCount 值,是的话就返回遍历;否则抛出异常,终止遍历。如果在集合遍历期间对其进行修改,就会改变 modCount 的值,进而导致 modCount != exceptedModCOunt,抛出异常。
阿里巴巴手册规定不要在 foreach 循环里进行元素的 remove/add 操作。要删除元素时使用 Iterator 的 remove 方法。如果并发操作,需要对 Iterator 对象加锁。
编辑 (opens new window)
上次更新: 2024/04/17, 21:30:18