1、是线程安全与线程不安全
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
2、分析
public boolean add(E e) {
/**
* 添加一个元素时,做了如下两步操作
* 1.判断列表的capacity容量是否足够,是否需要扩容
* 2.真正将元素放在列表的元素数组里面
*/
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
第二行,其实是执行
elementData[size] = e;
size= size+1;
为什么不安全?比如说,刚开始list为空。如果A线程要把a插入list,B线程要把b插入list,理想的情况应该是,size=2,list[0] = a,list[1]=b。然而,很可能是这样的:
A执行elementData[size] = e,此时 list[0]=a;
B再执行elementData[size] = e,此时A的值被覆盖,list[0] = b;
A执行size= size+1; 即1 = 0+1;
B执行size= size+1; 即2 = 1+1;
此时,第二个位置 list[1] = null
3、举一个线程不安全的例子
首先,ArrayList是线程不安全的,因为
public class TestArrayList {
public static void main(String[] args) throws InterruptedException{
//测试ArrayList是否是线程安全的,开两个线程,分别往list中添加0-9和10-19
TestArrayList tt = new TestArrayList();
ArrayList<Integer> list = new ArrayList<>();
//启动线程1
new Thread(new Runnable() {
public void run() {
tt.method1(list);
};
}).start();
//启动线程2
new Thread(new Runnable() {
public void run() {
tt.method2(list);
};
}).start();
Thread.sleep(1000);
// 打印所有结果
for (int i = 0; i < list.size(); i++) {
System.out.println("第" + (i) + "个元素为:" + list.get(i));
}
}
//线程1:在list中添加0-9
public void method1(ArrayList<Integer> list) {
for (int i = 0; i < 10 ; i++) {
list.add(i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//线程2:在list中添加10-19
public void method2(ArrayList<Integer> list) {
for (int i = 10; i < 20 ; i++) {
list.add(i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们设想得出的结果应该是:1,2,3…17,18,19。但是得出很多种结果,每次的都不一样:
第10个元素为:null
第11个元素为:15
第12个元素为:6
第13个元素为:16
4、如何变成线程安全
将
ArrayList<Integer> list = new ArrayList<>();
替换为:
List<Object> list = new Vector<Object>();
因为:ArrayList是非线程安全的,Vector是线程安全的;
执行结果:可以看到每一个轮回,都是线程1完全执行,再到线程2(或者先2后1)。不停交替
第0个元素为:0
第1个元素为:10
第2个元素为:11
第3个元素为:1
第4个元素为:2
第5个元素为:12
第6个元素为:3
第7个元素为:13
第8个元素为:4
第9个元素为:14
第10个元素为:5
第11个元素为:15
第12个元素为:16
第13个元素为:6
第14个元素为:17
第15个元素为:7
第16个元素为:18
第17个元素为:8
第18个元素为:9
第19个元素为:19
5、一些结论
ArrayList是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。