1

我有两个线程在修改同一个对象,比如说 MyObject,所以已经同步了这个对象。但在其中一个线程中,另一个对象被修改,因此必须调用 MyObject。

IE

public void run(){
   synchronized(MyObject){
             ...
            anotherObject.modify();//<----calls MyObject
             ...
    }
 }

这会导致 ConcurrentModificationExceptions。我不知道如何解决这个问题。如果我不同步,我会在两个线程都尝试调用 MyObject 时遇到异常。我怎样才能解决这个问题?

更新:代码适用于 Android 设备。我之前没有提到它,因为这里没有 Android 特定的对象在起作用。LogCat 输出不是很有帮助

02-03 02:47:43.660: ERROR/AndroidRuntime(5258): Uncaught handler: thread main exiting due to unaught exception 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): java.util.ConcurrentModificationException 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64) 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): at com.jjg .myapp.gameunit.findEnemy(MoveableUnit.java:656)//<---在这个方法中,Gamestate 的集合被迭代到 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): at com.jjg.myapp。 gameunit.update(GameUnit.java:416)

我试图同步的对象本质上是一个名为 gs 的 GameState。它包含各种 ArrayList、数组和其他对象。gs 不是静态的。

上面出现问题的方法是:

for(GameUnit gu : this.getBase().getGameState().getAllUnits()){//<---this is the problem line.
//do some stuff...
 }

getAllUnits 返回一个 GameUnits 的 ArrayList(包括调用该方法的 GameUnit - 我不需要迭代器,因为没有对象被删除或创建)。

4

4 回答 4

1

ConcurrentModificationException如果在使用迭代器时修改了集合,则通常会抛出A。- 所以我的你被名字误导了,只是寻找错误的问题。

于 2012-02-02T18:13:52.073 回答
1

您确实在问与此相同的问题:Thread-safe iteration over a collection

最简单的解决方案是在迭代之前复制列表:

for(GameUnit gu : new ArrayList<GameUnit>(this.getBase().getGameState().getAllUnits()))

或者,您可以在集合本身上进行同步(请注意,要使其正常工作,您还必须在修改“所有单位”列表的任何位置进行同步):

ArrayList<GameUnit> units = this.getBase().getGameState().getAllUnits())
synchronized (units) {
  ...
}
于 2012-02-02T18:24:48.823 回答
0

我有两个线程在修改同一个对象,比如说 MyObject,所以已经同步了这个对象。

不,你没有。只有 1 个线程正在修改MyObject另一个被阻止。

但在其中一个线程中,另一个对象被修改,因此必须调用 MyObject。

由于锁是租用的,因此拥有锁的线程将再次运行。

正如评论所述,您发布的代码并未显示您为获得该异常所做的实际操作。

MyObject一个Collection?您是否在其他地方同时修改此集合,即没有适当的同步?
或者也许是迭代?
在这种情况下,你会得到你说的异常

于 2012-02-02T18:21:15.533 回答
0

你不能这样做,这是循环逻辑。

您要么必须完全摆脱线程并确定明确的评估顺序,要么以其他方式共享数据。

一种可能的策略是将调用“anotherObject.modify”放入单独的可运行线程中,如下所示:

  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
       anotherObject.modify();
    }
  });
于 2012-02-02T18:24:29.960 回答