Space Invaders类游戏初始小行星生成Java报错求助
问题分析
java.util.ConcurrentModificationException 触发的核心原因有两个:要么是遍历集合的同时修改了集合结构(比如直接添加/删除元素),要么是多线程并发操作非线程安全的集合(比如ArrayList)。结合你的场景来看:
- 构造函数主线程生成小行星时,若定时器提前启动(哪怕是代码顺序问题导致的意外触发),两个线程会同时操作
asteroids集合; updateGameState里遍历小行星的过程中直接调用add()添加新小行星,属于遍历期间修改集合结构,必然触发异常。
解决方案
1. 严格控制初始化顺序:先生成初始小行星,再启动定时器
确保主线程完成所有初始小行星的创建后,再启动定时器,避免多线程并发操作集合:
// GamePanel构造函数修正 public GamePanel() { // 先完成基础组件初始化 this.setFocusable(true); this.requestFocus(); // ...其他初始化代码(比如火箭、子弹集合) // 第一步:生成初始NUM_OF_ASTEROIDS个小行星 asteroids = new ArrayList<>(); for (int i = 0; i < Globals.NUM_OF_ASTEROIDS; i++) { // 替换成你的小行星初始化逻辑,比如随机位置、速度 asteroids.add(new Asteroid( (int)(Math.random() * (getWidth() - Asteroid.WIDTH)), -Asteroid.HEIGHT, Globals.ASTEROID_SPEED )); } // 第二步:启动定时器 timer = new Timer(Globals.TIMER_DELAY, this); timer.start(); }
2. 安全处理遍历中的集合修改
不要在遍历asteroids的过程中直接添加/删除元素,改用迭代器删除,并用临时集合存储需要新增的小行星,遍历结束后批量添加:
private void updateGameState() { List<Asteroid> newAsteroids = new ArrayList<>(); // 使用迭代器遍历,避免遍历期间修改集合触发异常 Iterator<Asteroid> iterator = asteroids.iterator(); while (iterator.hasNext()) { Asteroid asteroid = iterator.next(); // 处理小行星移动、碰撞检测逻辑 asteroid.move(); // 判断是否被击毁 if (asteroid.isDestroyed()) { iterator.remove(); // 用迭代器安全删除元素 // 记录需要新增的小行星 newAsteroids.add(new Asteroid( (int)(Math.random() * (getWidth() - Asteroid.WIDTH)), -Asteroid.HEIGHT, Globals.ASTEROID_SPEED )); } // 其他逻辑:比如判断是否超出屏幕边界需要移除 else if (asteroid.getY() > getHeight()) { iterator.remove(); newAsteroids.add(new Asteroid(...)); } } // 遍历结束后,批量添加新小行星到原集合 asteroids.addAll(newAsteroids); }
3. 可选:给集合加线程同步(彻底解决多线程并发问题)
如果构造函数和定时器线程仍存在并发操作的可能,用Collections.synchronizedList包装集合,并在所有操作集合的地方加同步锁:
// 初始化线程安全的集合 private List<Asteroid> asteroids = Collections.synchronizedList(new ArrayList<>()); // 遍历和修改时都加同步锁 private void updateGameState() { List<Asteroid> newAsteroids = new ArrayList<>(); synchronized (asteroids) { Iterator<Asteroid> iterator = asteroids.iterator(); while (iterator.hasNext()) { // ...同上处理逻辑 } } synchronized (asteroids) { asteroids.addAll(newAsteroids); } }
验证步骤
- 替换构造函数的初始生成逻辑,确保先创建小行星再启动定时器;
- 调整
updateGameState的遍历和新增逻辑; - 启动游戏,检查是否还有异常,同时确认初始小行星正常生成、击毁后能自动补充。
内容的提问来源于stack exchange,提问作者kiwY12
相关产品推荐
相关产品推荐

