You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK1.8中Collections.sort()抛出ConcurrentModificationException的解决方法

解决ConcurrentModificationException异常的方案

异常原因

你遇到的ConcurrentModificationException是因为对ModuleManager.modules集合执行排序操作时,该集合被其他线程同时修改(比如模块启用/禁用时添加或移除元素),或是单线程下遍历过程中集合结构发生了变化。Collections.sort和List.sort内部会遍历集合,此时集合的结构修改会触发这个异常。

解决方案

方案1:操作集合副本而非原集合

创建原集合的快照副本,对副本进行排序和后续渲染操作,避免原集合的修改干扰排序过程:

public void onRender() {
    // 创建原集合的副本
    List<BaseModule> moduleCopy = new ArrayList<>(ModuleManager.modules);
    // 对副本执行排序
    Collections.sort(moduleCopy, new ModuleComparator());
    // 后续渲染逻辑使用moduleCopy而非原集合
}

也可以用Stream API简化写法:

import java.util.stream.Collectors;

public void onRender() {
    List<BaseModule> sortedModules = ModuleManager.modules.stream()
        .sorted(new ModuleComparator())
        .collect(Collectors.toList());
    // 使用sortedModules完成渲染
}

方案2:加锁保证线程安全

给ModuleManager.modules的所有访问操作(读取、修改、排序)加同步锁,确保同一时间只有一个线程操作集合:

  1. 在ModuleManager中定义全局锁对象:
public class ModuleManager {
    public static List<BaseModule> modules = new ArrayList<>();
    // 定义用于同步的锁对象
    public static final Object MODULE_LOCK = new Object();
}
  1. 排序时加锁:
public void onRender() {
    synchronized(ModuleManager.MODULE_LOCK) {
        Collections.sort(ModuleManager.modules, new ModuleComparator());
    }
}
  1. 所有修改modules的地方(比如添加/删除模块)必须同步加锁:
// 示例:添加模块时的加锁逻辑
synchronized(ModuleManager.MODULE_LOCK) {
    ModuleManager.modules.add(newModule);
}

方案3:改用线程安全集合

使用CopyOnWriteArrayList替代普通ArrayList,它的迭代器基于集合快照,不会抛出ConcurrentModificationException,适合读多写少的场景(比如模块开关操作频率低):

// 在ModuleManager中修改集合类型
import java.util.concurrent.CopyOnWriteArrayList;

public class ModuleManager {
    public static List<BaseModule> modules = new CopyOnWriteArrayList<>();
}

之后直接对原集合排序即可,无需额外处理:

public void onRender() {
    Collections.sort(ModuleManager.modules, new ModuleComparator());
}

额外修复:Comparator逻辑bug

你原有的ModuleComparator存在逻辑错误,两个if判断的条件完全相同,会导致排序结果不符合预期,修复如下:

public static class ModuleComparator implements Comparator<BaseModule> {
    @Override
    public int compare(BaseModule first, BaseModule second) {
        Minecraft mc = Minecraft.getMinecraft();
        int firstWidth = mc.fontRendererObj.getStringWidth(first.name);
        int secondWidth = mc.fontRendererObj.getStringWidth(second.name);
        
        if(firstWidth > secondWidth) {
            return -1; // 宽度大的模块排前面
        } else if(firstWidth < secondWidth) {
            return 1; // 宽度小的模块排后面
        }
        return 0;
    }
}

内容的提问来源于stack exchange,提问作者nekettt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 17:07:42