错误java.util.ConcurrentModificationException

现象描述:

cocos2d-x游戏移植android平台,运行时出现闪退,log如下:

06-17 13:12:25.020: E/AndroidRuntime(8053): FATAL EXCEPTION: GLThread 273
06-17 13:12:25.020: E/AndroidRuntime(8053): java.util.ConcurrentModificationException
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:792)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at java.util.HashMap$KeyIterator.next(HashMap.java:819)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at org.cocos2dx.lib.Cocos2dxSound.stopEffect(Cocos2dxSound.java:176)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at org.cocos2dx.lib.Cocos2dxHelper.stopEffect(Cocos2dxHelper.java:185)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at org.cocos2dx.lib.Cocos2dxRenderer.nativeRender(Native Method)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at org.cocos2dx.lib.Cocos2dxRenderer.onDrawFrame(Cocos2dxRenderer.java:94)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
06-17 13:12:25.020: E/AndroidRuntime(8053): 	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)

原因分析:

查看Cocos2dxSound.java的176行stopEffect方法

	public void stopEffect(final int pStreamID) {
		this.mSoundPool.stop(pStreamID);

		// remove record
		for (final String pPath : this.mPathStreamIDsMap.keySet()) {
			if (this.mPathStreamIDsMap.get(pPath).contains(pStreamID)) {
				this.mPathStreamIDsMap.get(pPath).remove(this.mPathStreamIDsMap.get(pPath).indexOf(pStreamID));
				break;
			}
		}
	}

我们注意到,在迭代时有remove操作,即进行了结构修改(增删操作),快速失败,因此抛出了ConcurrentModificationException.


解决方法:

由于我的游戏里的这个音效频繁播放,所以我用pauseEffect替代了stopEffect,一个偷懒的方案.

彻底的解决方法:

1).使用iterator来修改vector

2).使用conCurrentHashMap替代HashMap


扩展阅读:

快速失败:指某个线程在迭代vector的时候,不允许其他线程对vector进行结构性修改(增删操作,改值不算),如有修改,会抛出ConcurrentModificationException异常.

比如用iterator迭代userCollect时,iterator即另外起的一个线程,如果此时用userCollect.remove(obj)修改userCollect时,就会立刻抛出异常报错,不会等迭代结束才报错.

即时是单线程里,也是这样的.





`java.util.ConcurrentModificationException`异常通常发生在多线程环境下,当程序试图同时修改一个集合(如List、Set或Map)的内容,而这些集合是被其他线程正在遍历的时候。这是因为Java的集合类内部维护了一个迭代器,这个迭代器假设集合的内容不会改变,但在并发情况下,如果线程A正在遍历,线程B修改了集合,就会导致迭代器无法正确跟踪元素,从而抛出此异常。 要解决这个问题,可以采取以下几种策略: 1. **避免在迭代过程中修改集合**:如果你知道可能会有修改,尽量在遍历之前完成所有可能的修改操作,或者使用不可变集合(如`Collections.unmodifiableList()`)。 2. **同步操作**:如果必须在迭代过程中修改,确保对集合的修改操作是在同步块中进行,这样可以保证同一时间只有一个线程可以修改集合。 3. **使用并发集合**:Java提供了一些并发版本的集合,如`CopyOnWriteArrayList`和`ConcurrentHashMap`,它们在修改时会创建新的视图,避免了直接抛出异常,而是返回一个新的结果。 4. **使用`Iterator.remove()`替换`List.remove()`**:在`List`迭代器上调用`remove()`方法时,不会抛出`ConcurrentModificationException`,但会导致迭代提前结束。 在你给出的代码示例中,删除元素时引发异常是因为尝试在线程安全的迭代中修改了集合结构。正确的做法是先移除元素再迭代,或者在遍历时使用`Iterator.remove()`替换`List.remove()`。 ```java // 错误示例 List<Integer> list = ...; Iterator<Integer> it = list.iterator(); while (it.hasNext()) { if (it.next().equals(3)) { // 不应在迭代过程中修改 it.remove(); // 这里会抛出异常 } } // 正确示例 List<Integer> list = ...; Integer target = 3; list.remove(target); // 先移除元素 for (Integer element : list) { // 现在可以安全地遍历 } ``` [^1]: java.util.ConcurrentModificationException异常原因及解决方法。@TOC 欢迎使用Markdown编辑器 : java.util.ConcurrentModificationException异常原因及解决方法。复制代码 上述代码在删除value=3的元素时,报java.util.ConcurrentModificationException异常,如下图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值