Kotlin使用list.map()时如何避免ConcurrentModificationException
可行解决方案
方案1:使用集合快照(最省事,适合统计允许存在毫秒级延迟的场景)
你担心的创建临时列表的方案实际开销极低,完全不存在不合理的问题,是绝大多数场景下的最优解。同时Kotlin标准库已经封装了求和方法,不需要手动写累加逻辑:
// 生成当前集合的不可变快照,后续操作完全和原集合无关 val currentSnapshot = arrDeltaBrainWaves.toList() // 直接调用sum方法求和,无需手动遍历累加 val deltaSum = currentSnapshot.sum() avgDelta = deltaSum / currentSnapshot.size
注意:该方案统计的是生成快照瞬间的集合数据,生成快照后原集合的改动不会影响本次统计结果
方案2:全局加锁保证读写互斥(适合要求统计数据绝对实时精准的场景)
给集合的所有读写操作绑定同一把锁,保证遍历统计的过程中不会有其他线程修改集合,从根源避免并发修改冲突:
// 全局定义和该集合绑定的锁,所有对arrDeltaBrainWaves的读写操作都必须持有该锁 val collectionLock = Any() // 统计逻辑 synchronized(collectionLock) { val deltaSum = arrDeltaBrainWaves.sum() avgDelta = deltaSum / arrDeltaBrainWaves.size } // 其他位置修改集合的逻辑也要加相同的锁,示例: synchronized(collectionLock) { arrDeltaBrainWaves.add(newValue) }
方案3:直接使用线程安全集合(适合高频读写的场景)
初始化集合时直接使用JDK自带的CopyOnWriteArrayList,该集合的遍历操作默认基于快照实现,天然不会抛出ConcurrentModificationException,无需额外加锁或者手动复制快照:
// 初始化阶段替换集合实现即可 val arrDeltaBrainWaves = CopyOnWriteArrayList<Int>() // 后续统计直接调用方法即可 val deltaSum = arrDeltaBrainWaves.sum() avgDelta = deltaSum / arrDeltaBrainWaves.size
额外优化建议
你之前用map做累加属于API误用,map是用来做集合元素转换生成新集合的操作,纯副作用的遍历应该用forEach,求和、求平均这类通用统计逻辑直接用标准库封装的sum()、average()方法即可,代码更简洁也不容易出错。
内容的提问来源于stack exchange,提问作者Beesz
相关产品推荐
相关产品推荐

