在Java中同步线程

时间:2012-02-02 18:04:21

标签: java android multithreading synchronized concurrentmodification

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

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

这导致ConcurrentModificationExceptions。我不知道如何解决这个问题。如果我不同步,我会得到异常,因为两个线程都试图调用MyObject。我该如何解决这个问题?

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

  

02-03 02:47:43.660:ERROR / AndroidRuntime(5258):未捕获的处理程序:由于未捕获的异常而导致主线程退出   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)//&lt; ---在此方法中,Gamestate的集合通过迭代完成   02-03 02:47:43.670:ERROR / AndroidRuntime(5258):at com.jjg.myapp.gameunit.update(GameUnit.java:416)

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

出现问题的上述方法是:

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

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

4 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分: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) {
  ...
}

答案 2 :(得分:0)

  

我有两个线程修改同一个对象,比方说MyObject,和   所以已同步对象。

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

  

但是在其中一个线程中,另一个对象被修改并且这样做   必须调用MyObject。

由于锁是租用的,具有锁的线程将再次出现。

正如评论所述,您发布的代码并未显示您实际执行的操作以获取该异常。

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

答案 3 :(得分:0)

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

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

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

  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
       anotherObject.modify();
    }
  });