ArrayList的线程安全问题

  ArrayList是不安全的。多个线程对ArrayList操作,会出现问题。

实例1

  下面这个demo,主要测试内容:三个线程,一个线程向集合中add数据,一个线程从集合中remove数据,一个线程判断如果集合中有数据,从其中获取数据。运行程序,会报错:越界异常。
  以下是异常图片:

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ArrayListThreadTest {
// private static List<String> TEST_LIST = new CopyOnWriteArrayList<String>();
private static List<String> TEST_LIST = Collections.synchronizedList(new ArrayList<String>());
// private static List<String> TEST_LIST = new ArrayList<>();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
TEST_LIST.add("11");
System.out.println("Thread1 running");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
TEST_LIST.clear();
System.out.println("Thread2 running");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (TEST_LIST.size() > 0) {
int size = TEST_LIST.size();
System.out.println(size + "====");
System.out.println(size + "===" + TEST_LIST.get(size-1));
}
// System.out.println("Thread3 running");
}
}
}).start();
}
}

实例2

  演示内容:多个线程向集合arraylist、线程安全的arraylist中添加数据,集合长度不同。
  下面例子则来源于:http://www.oschina.net/code/snippet_70229_2425

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
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
// Java语言: ArrayList的线程安全与不安全对比演示
public class ThreadSafeDemo {
public static int demo(final List list, final int testCount) throws InterruptedException {
ThreadGroup group = new ThreadGroup(list.getClass().getName() + "@" + list.hashCode());
final Random rand = new Random();
Runnable listAppender = new Runnable() {
public void run() {
try {
Thread.sleep(rand.nextInt(2));
} catch (InterruptedException e) {
return;
}
list.add("0");
}
};
for (int i = 0; i < testCount; i++) {
new Thread(group, listAppender, "InsertList-" + i).start();
}
while (group.activeCount() > 0) {
Thread.sleep(10);
}
return list.size();
}
public static void main(String[] args) throws InterruptedException {
List unsafeList = new ArrayList();
List safeList = Collections.synchronizedList(new ArrayList());
final int N = 10000;
for (int i = 0; i < 10; i++) {
unsafeList.clear();
safeList.clear();
int unsafeSize = demo(unsafeList, N);
int safeSize = demo(safeList, N);
System.out.println("unsafe/safe: " + unsafeSize + "/" + safeSize);
}
}
}

总结

  ArrayList是线程不安全的,多线程中,我们可以使用Collections.synchronizedList(list);方法使其转换成安全的。或者我们也可以调用自己写的get、set、remove方法方法,自己方法内部加锁,调用list的get、set、remove方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TestList {
public static List<String> list = new ArrayList<>();
public static void addMessage(String message){
synchronized (TestList.class) {
list.add(message);
}
}
public static void getMessage(String message){
synchronized (TestList.class) {
if (list.size() > 0) {
list.remove(0);
}
}
}
}

文章目录
  1. 1. 实例1
  2. 2. 实例2
  3. 3. 总结
|