ArrayList为什么不是线程安全的?
ArrayList在日常的开发中,不会出问题的原因是大多数应用场景都是单线程的,如果使用多线程来操作同一个ArrayList对象,就会引发线程安全问题。
至于原因来看看ArrayList 的 java.util.ArrayList.add(E)方法:
1
2
3
4
5
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
很明显,它的add方法没有加上synchronized关键字,导致它并不是一个同步的代码块。
怎么解决ArrayList的线程安全问题呢?
假设在面试中,由ArrayList是否是线程安全的引出了如何解决的问题
最好不要言简意赅的回答:加锁,因为这是面试,对你的考查并不是想听你说这个,更想听到的答案是以下解决方案
1
2
3
4
5
1、new Vector<>();
2、Collections.synchronizedList(new ArrayList<>());
3、new CopyOnWriteArrayList<>();
那么来看看具体的代码Demo,看看相关注释。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* JDK 1.8
* @author nobt
*
*/
public class ArrayListSafe {
public static void main(String[] args) {
/*
* //在单机版/单线程环境中不会出错,但是在多线程环境中大概率报异常:java.util.ConcurrentModificationException
* //以下注释代码可以单独执行一次,会报以上异常
* List<String> list = new ArrayList<>();
*
* for (int i = 1; i < 30; i++) {
* new Thread(() -> {
* list.add(UUID.randomUUID().toString().substring(0, 8));
* System.out.println(list); }).start();
* }
*/
/*
* 解决办法
* 这里值得注意的是,在面试当中,如果由以上代码引出的安全问题,面试官提问解决办法?
* 最好不要言简意赅的回答:加锁,因为这是面试,对你的考查并不是想听你说这个,更想听到的答案是以下解决方案
* 1、new Vector<>();
* 2、Collections.synchronizedList(new ArrayList<>());
* 3、new CopyOnWriteArrayList<>();
*/
// 1、new Vector<>();
List<String> vectorList = new Vector<>();
for (int i = 1; i < 30; i++) {
new Thread(() -> {
vectorList.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(vectorList);
}).start();
}
// 2、Collections.synchronizedList(new ArrayList<>());
//这种做法中可以看到Collections辅助类支持的其它集合肯定也是存在线程安全问题的,比如Collections.synchronizedMap(m)、Collections.synchronizedSet(s)...
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i < 30; i++) {
new Thread(() -> {
synchronizedList.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(synchronizedList);
}).start();
}
// 3、new CopyOnWriteArrayList<>();
List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
for (int i = 1; i < 30; i++) {
new Thread(() -> {
copyOnWriteArrayList.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(copyOnWriteArrayList);
}).start();
}
}
}