在Dispatchers.Default中操作列表遇ConcurrentModificationException需拆分代码块吗?
解决Dispatchers.Default中列表操作引发的ConcurrentModificationException问题
问题分析
你遇到的java.util.ConcurrentModificationException,核心原因不是把更新和排序放在同一个Dispatchers.Default块里,而是当前代码的迭代方式存在风险,或者listOfLocation被其他线程/协程并发修改了:
- 你用
for (item in listOfLocation)的方式迭代列表,这种迭代依赖于列表的迭代器,而迭代器会维护内部的修改计数。如果迭代过程中通过indexOf定位元素并替换(尤其是当列表存在重复元素时,indexOf可能返回错误索引),或者其他线程同时修改了列表结构,就会触发异常。 - 拆分到两个独立的
Dispatchers.Default块完全没必要,反而可能因为中间其他线程介入修改列表,加重并发问题。
修复方案
1. 改用索引迭代,避免迭代器冲突
把迭代方式换成基于索引的循环,直接通过下标访问和替换元素,彻底规避迭代器的修改计数校验问题:
withContext(Dispatchers.Default) { for (i in listOfLocation.indices) { val item = listOfLocation[i] val distanceInMeter = ClsGlobel.calculateDistance( item.lat, item.lon, it.latitude, it.longitude ) * 1000 listOfLocation[i] = SavedLocation(item.id, item.lat, item.lon, distanceInMeter, item.areaName) } listOfLocation.sortBy { it.distance } Log.e("tag", " Default: " + Thread.currentThread().name) }
2. 确保列表的线程安全性
如果listOfLocation会被多个线程/协程同时读写,必须使用线程安全的集合(比如CopyOnWriteArrayList),或者在所有访问该列表的代码块中加锁(比如用synchronized),避免并发修改。
总结
不需要拆分更新和排序的逻辑到两个Dispatchers.Default块里。调整迭代方式,同时保证列表不会被并发修改,就能解决ConcurrentModificationException异常。
内容的提问来源于stack exchange,提问作者karan
相关产品推荐
相关产品推荐

