线程安全与线程不安全

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是线程安全的。

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值