Java和同步两个线程
Posted
技术标签:
【中文标题】Java和同步两个线程【英文标题】:Java and Synchronizing two threads 【发布时间】:2012-05-12 10:59:12 【问题描述】:我有两个线程修改相同的对象。这些对象是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
?还是应该将ArrayList
更改为Vector
?
【问题讨论】:
【参考方案1】:ConcurrentModificationException 并非源于修改集合中的对象,而是源于在迭代器处于活动状态时从集合中添加/删除。
共享资源是集合,必须有第三种方法使用和添加/删除。要获得正确的并发性,您必须在访问它的所有方法中同步对集合资源的访问。
为避免同步块过长,一种常见的模式可能是将集合复制到同步块中,然后对其进行迭代。如果您这样做,请注意您首先谈论的问题(对象的并发修改)再次出现 - 但这次您可以锁定另一个资源。
【讨论】:
【参考方案2】:您不需要同步对列表的访问,只要您不对其进行结构性修改,即只要您不从列表中添加或删除对象。你也不应该看到ConcurrentModificationException
s,因为只有在你对列表进行结构性修改时才会抛出这些。
因此,假设您只修改列表中包含的对象,但不添加或删除或重新排序列表中的对象,则可以在修改时对包含的对象进行同步,如下所示:
void modifyAgain(MyObject x)
synchronized(x)
// do the modification
我不会在 modifyAgain()
方法上使用 synchronized
修饰符,因为这不允许同时修改列表中的两个不同对象。
另一个线程中的modify()
方法当然必须和modifyAgain()
一样实现。
【讨论】:
【参考方案3】:您需要在同一个锁上同步访问集合,因此仅在方法上使用同步关键字(假设它们在不同的类中)将锁定两个不同的对象。
所以这里是你可能需要做的一个例子:
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);
您也可以考虑使用CopyOnWriteArrayList
而不是Vector
【讨论】:
【参考方案4】:我猜你的问题与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);
为了获得更好的结果,我希望有人纠正我的解决方案。
【讨论】:
以上是关于Java和同步两个线程的主要内容,如果未能解决你的问题,请参考以下文章