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

设置集合大小判断条件仍触发数组越界异常求助(多人游戏场景)

针对数组越界异常的排查与解决方案

看起来你遇到的是典型的并发场景下的竞态条件问题,虽然你加了边界判断,但判断和实际访问集合之间的窗口里,集合的状态可能已经被修改了,尤其是在多人在线游戏这种多线程/多设备同步的环境中。结合单台设备崩溃的情况,我整理了几个核心原因和对应的解决思路:

核心原因分析

1. 并发修改导致的竞态条件

当你执行if (mSecondCount < mUsedItem.size())时,mUsedItem的大小是符合条件的,但在你调用mUsedItem.get(mSecondCount)之前,另一个线程(比如游戏逻辑线程、网络同步线程)可能已经移除了mUsedItem中的元素,导致集合size变小,此时mSecondCount就会超出新的边界,触发IndexOutOfBoundsException。

这种情况在非线程安全的集合(比如ArrayList)中尤为常见,因为size()方法和get()方法都没有同步机制,无法保证判断和访问的原子性。

2. 单台设备的特殊数据同步问题

既然只有单台设备崩溃,大概率是这台设备的本地集合状态和其他设备/服务器不一致。比如网络延迟导致本地没有及时收到服务器下发的集合更新指令,当mSecondCount递增后,本地集合已经被清空或元素减少,但你的边界判断还是基于旧的size值。

具体解决方案

方案1:确保判断与访问的原子性

把边界判断和集合访问逻辑放在同一个同步块中,避免中间被其他线程修改:

// 用集合本身作为锁对象,确保同一时间只有一个线程操作它
synchronized(mUsedItem) {
    if (mSecondCount < mUsedItem.size()) {
        if (mUsedItem.get(mSecondCount).getItemNum() == 5) {
            // 你的业务逻辑
        }
    }
}

方案2:改用线程安全的集合

如果你的场景是读多写少,可以替换为CopyOnWriteArrayList——它会在每次修改时复制一份底层数组,保证读操作的线程安全性,不会出现并发修改导致的异常:

// 初始化时替换为线程安全集合
List<YourItemType> mUsedItem = new CopyOnWriteArrayList<>();

如果是频繁修改的场景,可以考虑ConcurrentLinkedQueue(适合队列操作)或者其他并发集合类。

方案3:增加二次索引校验

虽然有点冗余,但可以在get操作前再做一次边界判断,覆盖极端情况下的竞态条件:

if (mSecondCount < mUsedItem.size()) {
    // 二次校验,防止判断后集合size突变
    if (mSecondCount >= 0 && mSecondCount < mUsedItem.size()) {
        if (mUsedItem.get(mSecondCount).getItemNum() == 5) {
            // 你的业务逻辑
        }
    }
}

方案4:排查单台设备的同步逻辑

针对单台设备的崩溃,建议:

  • 收集该设备崩溃时的详细日志,记录mSecondCount的具体值和mUsedItem.size()的实际值,确认是否是同步延迟导致的size不一致;
  • 检查该设备的网络状态,是否存在丢包、延迟过高的情况;
  • 验证服务器下发的集合更新指令是否在本地正确处理,有没有遗漏的回调或异常吞掉了更新逻辑。

内容的提问来源于stack exchange,提问作者Dexter.Z

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:05:41