java.util.ConcurrentModificationException高并发修改导致的异常

本文详细解析了Java中处理线程安全问题的两种方法:使用synchronized关键字和Lock接口,通过实例展示了如何避免多线程操作ArrayList时产生的ConcurrentModificationException异常。

Java中,如果一个对象不是线程安全的。那么再高并发的情况下多个线程同时需要对这个对象进行修改则会出现此异常

解决方法:

1、使用synchronized关键字

		List list = new ArrayList();
        Object lock = new Object();
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                synchronized (lock){
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }
            },String.valueOf(i)).start();
        }

这个例子中的lock是一个object对象。使用synchronized 获取该对象并且锁定资源。其他线程就无法获取到该lock对象。等到synchronized代码块执行完毕后该对象锁会自动释放,其他线程才能获取lock对象资源并上锁,然后在执行代码块。

2、使用Lock接口

		Lock lock = new ReentrantLock();
        List list = new ArrayList();
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                lock.lock();
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
                lock.unlock();
            },String.valueOf(i)).start();
        }

ArrayList本是线程不安全的对象,所以在多线程同时进行数据添加的时候可能会出现ConcurrentModificationException异常。经过上面的代码处理则解决掉了这个问题。这里用ArrayList只是举例说明Lock的使用。
实际开发过程中ArrayList不用我门手动添加Lock。使用CopyOnWriteArrayList来代替ArrayList就可以了,查看CopyOnWriteArrayList可以看见它也是使用同样的方式来保证线程安全

    /**
     * CopyOnWriteArrayList中的源码
     */
    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();
        }
    }
### 解决 Android Java 开发中的 `java.util.ConcurrentModificationException` 异常 #### 使用迭代器的安全移除方法 为了安全地遍历并修改集合,应该使用迭代器提供的 `remove()` 方法而不是直接调用集合对象的方法。这能确保在迭代过程中不会引发并发修改异常。 ```java import java.util.*; class SafeRemovalExample { public static void main(String[] args){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; ++i) { list.add(i); } Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ int value = iterator.next(); if(value == 5){ iterator.remove(); // 安全地移除元素 } else{ System.out.println(value); } } } } ``` #### 利用线程同步机制 当多个线程访问同一个列表时,可以通过锁机制来保护共享资源,从而避免并发冲突。例如,在多线程环境中操作 `ArrayList` 可以采用显式的锁定策略: ```java ReentrantLock lock = new ReentrantLock(); // 在执行增删改查之前先获取锁 lock.lock(); try { // 对list的操作... } finally { lock.unlock(); // 不管是否发生异常都要释放锁 } ``` #### 替换为支持并发的数据结构 对于高并发场景下的频繁读写需求,考虑选用更合适的支持并发操作的数据结构,比如 `CopyOnWriteArrayList` 或者 `ConcurrentHashMap` 等替代品。这些类内部实现了必要的同步控制逻辑,能够更好地适应复杂的并发环境[^2]。 #### 处理 RecyclerView 数据更新 针对 `RecyclerView` 的适配器管理的数据源变化引起的问题,建议采取批量刷新的方式代替逐项更改数据集的做法;另外也可以通过通知特定位置的变化而非整体重绘的方式来优化性能表现,减少不必要的重新布局计算开销[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值