解决--java.util.ConcurrentModificationException

一直都说ArrayList是线程不安全的,只知其话,不懂其意,今天终于碰到了


举例如下:

单线程情况下:—>运行正常

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
                list.add(UUID.randomUUID().toString().substring(0, 6));//加入字符串
                System.out.println(list);//读取list
        }
    }

线程不安全,那么好,将ArrayList放入多线程中

举例如下:

多线程情况下:—>运行出异常

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 6));
                System.out.println(list);
            }, "A").start();
        }
    }

如下错误:并发修改异常
在这里插入图片描述


原因分析

并发修改异常,指的是在多线程情况下线程争抢同一资源时读写出错。 例如:大巴车开车和顾客上车,大巴车行驶时是不能上乘客的,上乘客的时候大巴车不允许开车,当同时开车并同时上乘客就会出现危险。

查看ArrayList源码如下:
在这里插入图片描述


解决思路

  • 既然 ArrayList 是线程不安全的,那就使用线程安全的集合,例如使用 Vector
  • 可不可以让 ArrayList 变成线程安全的
  • 既然是读写时出现的错误,是不是可以让读写分开(这一点值得思考 --> 写时复制技术)
解决方案一:使用线程安全的集合
    public static void main(String[] args) {
//
        List<String> list = new Vector<>();
//     
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 6));
                System.out.println(list);
            }, "A").start();
        }
    }

解决方案二:将ArrayList变成线程安全
    public static void main(String[] args) {
//    
        List<String> list = Collections.synchronizedList(new ArrayList<>());
//            
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 6));
                System.out.println(list);
            }, "A").start();
        }
    }
解决方案三:读写分离–>写时复制技术
    public static void main(String[] args) {
//
        List<String> list = new CopyOnWriteArrayList<>();
//
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 6));
                System.out.println(list);
            }, "A").start();
        }
    }

写时复制技术

1.什么是写时复制技术?

写时复制是指: 在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的容器(副本容器)。

2.写时复制带来的影响

① 由于不会修改原始容器,只修改副本容器。因此,可以对原始容器进行并发地读。其次,实现了读操作与写操作的分离,读操作发生在原始容器上,写操作发生在副本容器上。

② 数据一致性问题:读操作的线程可能不会立即读取到新修改的数据,因为修改操作发生在副本上。但最终修改操作会完成并更新容器,因此这是最终一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值