1

我有两个线程修改相同的对象。ArrayList对象是(不是向量)中的自定义、非同步对象。我想让这两个线程很好地协同工作,因为它们是同时被调用的。

这是线程 1 中唯一重要的方法。

public void doThread1Action() {
  //something...
  for(myObject x : MyArrayList){
    modify(x);
  }
}

这是线程2中的一个方法:

public void doThread2Action() {   
  //something...
  for(myObject x : MyArrayList){
    modifyAgain(x);
  }
}

目前,在测试时,我偶尔会遇到`ConcurrentModificationExceptions`。(我认为这取决于线程 1 在线程 2 尝试修改对象之前完成迭代的速度。)

我是否认为通过简单地附加synchronized到这两种方法的开头,线程将以同步的方式一起工作,而不是尝试访问ArrayList?或者我应该将 更改ArrayListVector

4

4 回答 4

3

ConcurrentModificationException 不是源于修改集合中的对象,而是源于在迭代器处于活动状态时从集合中添加/删除。

共享资源是集合,必须有第三种方法使用和添加/删除。要获得正确的并发性,您必须在访问它的所有方法中同步对集合资源的访问。

为了避免同步块过长,一种常见的模式可能是将集合复制到同步块中,然后对其进行迭代。如果您这样做,请注意您首先谈论的问题(对象的并发修改)再次出现- 但这次您可以锁定另一个资源。

于 2012-05-12T11:03:34.960 回答
0

您不需要同步对列表的访问,只要您不对其进行结构修改,即只要您不从列表中添加或删除对象。您也不应该看到ConcurrentModificationExceptions,因为仅当您在结构上修改列表时才会抛出这些。

因此,假设您只修改列表中包含的对象,但不添加、删除或重新排序列表中的对象,则可以在修改时同步包含的对象,如下所示:

void modifyAgain(MyObject x) {
    synchronized(x) {
        // do the modification
    }
}

我不会synchronized在方法上使用修饰符modifyAgain(),因为这不允许同时修改列表中的两个不同对象。

另一个线程中的modify()方法当然必须以与modifyAgain().

于 2012-05-12T11:14:25.760 回答
0

您需要在同一个锁上同步访问集合,因此仅在方法上使用同步关键字(假设它们在不同的类中)将锁定两个不同的对象。

所以这里有一个你可能需要做的例子:

Object lock = new Object();

public void doThread1Action(){

//something...
    synchronized(lock){
        for(myObject x : MyArrayList){
           modify(x);
    }

}

public void doThread2Action(){

//something...
    synchronized(lock){
        for(myObject x : MyArrayList){
            modifyAgain(x);
    }

}

您也可以考虑使用 aCopyOnWriteArrayList而不是Vector

于 2012-05-12T11:19:16.513 回答
0

我猜你的问题与ConcurrentModificationException. 这个类在它的 Java 文档中说:

/** * 当这种修改是不允许的时,
检测到对象的并发修改的方法可能会抛出此异常。

*/

在您的情况下,问题是列表中的迭代器并且可能会被修改。我想通过以下实现你的问题将是唯一的:

public void doThread1Action()
{
    synchronized(x //for sample)
    {
       //something...
       for(myObject x : MyArrayList)
       {
          modify(x);
       }
    }
}

接着:

public void doThread2Action()
{
    synchronized(x //for sample)
    {
       //something...
       for(myObject x : MyArrayList)
       {
          modifyAgain(x);
       }
    }
}

为了获得更好的结果,我希望有人纠正我的解决方案。

于 2012-05-12T11:19:40.067 回答