代码展示

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.List;
import java.util.ArrayList;
import java.util.Collections;

public class ThreadSafeVisualPerformanceTest {

public static int multithreadingToAddData(List<String> list, String name) {

ThreadGroup threadGroup = new ThreadGroup(name);

Runnable runnable = () -> {

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}

list.add("0");

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
};

for (int i = 0; i < 100; i++) new Thread(threadGroup, runnable).start();

while (threadGroup.activeCount() > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

return list.size();

}

public static void main(String[] args) {

List<String> nonThreadSafeCollection = new ArrayList<>(),
/* 使用Collections.synchronizedList方法将ArrayList转换成线程安全的集合 */
threadSafeCollection = Collections.synchronizedList(new ArrayList<>());

for (int i = 0; i < 3; i++) {

/* 清除集合 */
nonThreadSafeCollection.clear();
threadSafeCollection.clear();

int size1 = multithreadingToAddData(nonThreadSafeCollection, "线程不安全集合"),
size2 = multithreadingToAddData(threadSafeCollection, "线程安全集合");

System.out.println("线程不安全集合添加元素数量为: " + size1 + ", 线程安全集合添加元素数量为" + size2);

}
}
}

打印展示

此处的异常信息为线程不安全的ArrayList集合在多线程中会出现线程抢占,从而导致了集合越界

多线程

内存角度分析异常原因

内存

1
2
3
在Java虚拟机中,内存分为线程内存和主内存;对于每一个线程而言,线程内存会从主内存中读取数据到本地内存,在完成操作后再回写到主内存中
1.线程安全对象: 读取、回写是受控制的
2.线程不安全对象: 会有多个线程同时读取数据到本地,然后出现线程抢占(一个线程还未完成操作,另外一个线程的操作就继续了,另外一个线程的操作就将它的操作冲掉了)

线程安全与线程不安全的对象

1
2
线程安全对象: Vector, HashTable, StringBuffer
线程不安全对象: ArrayList, LinkedList, HashMap, StringBuilder

将线程不安全的对象包装成线程安全的对象的方法

1
2
3
1.List类: Collections.synchronizedList(list)
2.Set类: Collections.synchronizedSet(set)
3.Map类: Collections.synchronizedMap(map)