集合类高并发线程不安全及解决方案

线程不安全综述

线程不安全案例

public static void main(String[] args) {
        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);
            }, String.valueOf(i)).start();
        }
}

运行时会报错

java.util.ConcurrentModificationException

原因分析

举个例子,就好比上课前签到,每个人都有一支笔,但是只有一张签到纸。张三在纸上签到,‘张’字刚写完,李四就过来强硬的把纸拉走,要签到,但是在拉的过程中,张三的笔就会在纸上留下长长的划痕。然后李四签到。有可能李四签到完成正常轮到下一位,也有可能李四还没签完就又被抢走了。

上面例子中,拿着笔的同学就好比是线程,在抢夺‘纸’的过程中在‘纸’上留下的划痕就好比是程序抛的异常。

解决方案

1. List list = new Vector<>();

Vector底层都有synchronized封装,可以保证线程安全。

2. List list = Collections.synchronizedList(new ArrayList<>());

用Collections包装类的synchronizedList方法将ArrayList包装起来,ArrayList也可以变成线程安全。

3.List list = new CopyOnWriteArrayList<>();

写时复制
CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器object[]添加,而足先将当前容器object[]进行copy,复制出一个新的 容器Object[] newElements, 然后新的容器object[] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements);。这样做的好处是可以对Copyonwrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnwrite容器也是一种读 写分离的思想,读和写不同的容器。

public boolean add(E e){
	final ReentrantLock Lock = this.lock;
		lock.lock();
	try{
		object[] elements = getArray();|
		int Len = elements.Length;
		object[] newElements = Arrays.copyof(elements, len + 1);
		newELements[len] = e;
		setArray(newELements);
		return true;
	}finally {
		lock. unlock();
	}
}

举个例子,还是上面的签到,比如前面已经有一些同学签到了,轮到张三签到了,张三会把签到表抄一份一模一样的到自己手里(上面的数组复制,并且长度+1,因为指望里面添加一个元素(姓名)),然后在最后面加上自己的名字,然后把手里的签到表公布出来,说:“现在的签到表以这份为准,以前的签到表已经作废。”(这里setArray将新的集合作为标准,以前的指针指向打断了)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值