我正在尝试运行2个并发线程,其中一个不断添加对象到列表,另一个更新这些对象,也可以从列表中删除其中的一些对象。
我有一个完整的项目,我已经将ArrayList
用于我的方法和类,所以现在很难改变它。
我环顾四周,找到了一些方法,但正如我所说,很难从ArrayList
改变。我尝试将synchronized
和notify()
用于将对象添加到列表中的方法,并尝试使用wait()
来更改这些对象,并在符合特定条件的情况下删除它们。
现在,我已经想出了如何使用CopyOnWriteArrayList
来做到这一点,但我想知道是否有可能使用ArrayList
本身来模拟这个。所以我不必编辑我的整个代码。
所以,基本上,我想做这样的事情,但ArrayList
:
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class ListExample{
CopyOnWriteArrayList<MyObject> syncList;
public ListExample(){
syncList = new CopyOnWriteArrayList<MyObject>();
Thread thread1 = new Thread(){
public void run(){
synchronized (syncList){
for(int i = 0; i < 10; i++){
syncList.add(new MyObject(i));
}
}
}
};
Thread thread2 = new Thread(){
public void run(){
synchronized (syncList){
Iterator<MyObject> iterator = syncList.iterator();
while(iterator.hasNext()){
MyObject temp = iterator.next();
//this is just a sample list manipulation
if (temp.getID() > 3)
syncList.remove(temp);
System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size());
}
}
}
};
thread1.start();
thread2.start();
}
public static void main(String[] args){
new ListExample();
}
}
class MyObject{
private int ID;
public MyObject(int ID){
this.ID = ID;
}
public int getID(){
return ID;
}
public void setID(int ID){
this.ID = ID;
}
}
我还阅读了关于Collections.synchronizedList(new ArrayList())
但又一次,我相信这需要我更改我的代码,因为我有大量的方法将ArrayList
作为参数。
任何指导都会受到赞赏,因为我没有想法。谢谢。
答案 0 :(得分:4)
您可能对java.util.concurrent
包提供的馆藏感兴趣。它们对于生产者/消费者场景非常有用,其中一个或多个线程将事物添加到队列中,而其他线程则使用它们。根据您是要阻塞还是在队列满/空时失败,有不同的方法。
关于重构方法,您应该使用接口(例如List
)而不是具体的实现类(例如ArrayList
)。这就是接口的目的,Java API有很好的支持。
答案 1 :(得分:1)
作为一种快速解决方案,您可以扩展ArrayList并使修改方法(添加/删除)同步。并重新分解代码以将ArrayList替换为您的custom-ArrayList
答案 2 :(得分:0)
使用Vector
代替ArrayList
。请记住将其存储在List
引用中,因为Vector包含不推荐使用的方法。与ArrayList不同,Vector同步其内部操作,与CopyOnWriteArrayList
不同,每次进行修改时都不会复制内部数组。
答案 3 :(得分:0)
当然你应该使用java.util.concurrent
pakage。但是,让我们看一下仅ArrayList
和同步发生/可能发生的事情。
在您的代码中,如果您只有ArrayList
代替CopyOnWriteArrayList
,那么它应该可以正常运行,因为您在线程中正在执行/操作的任何内容都提供了完全同步synchronized (syncList)
。如果整个事情是同步的,你不需要任何wait()
notify()
(但不建议这样做)。
但是这段代码会给ConcurrentModificationException
,因为一旦你使用了iterator syncList.iterator()
,就不应该从该列表中删除元素,否则它会在迭代时产生不良结果,这就是为什么它设计为快速失败并给出例外。为避免这种情况,您可以使用:
Iterator<MyObject> iterator = syncList.iterator();
ArrayList<MyObject> toBeRemoved = new ArrayList<MyObject>();
while(iterator.hasNext()){
MyObject temp = iterator.next();
//this is just a sample list manipulation
if (temp.getID() > 3)
{
//syncList.remove(temp);
toBeRemoved.add(temp);
}
System.out.println("Object ID: " + temp.getID() + " AND list size: " + syncList.size());
}
syncList.removeAll(toBeRemoved);
现在关于同步,你应该努力最小化它的范围,否则线程之间会有不必要的等待,这就是为什么java.util.concurrent包在多线程中具有高性能(甚至使用非阻塞算法)。或者您也可以使用Collections.synchronizedList(new ArrayList())
,但它们不如concurrent
类。
如果要在生产者/消费者问题中使用条件同步,则可以在同一对象(锁定)上使用wait()
notify()
机制。但是,已经有一些类可以帮助您使用java.util.concurrent.LinkedBlockingQueue
。