我有一个预先填充的数组列表。我有多个线程将从数组列表中删除元素。每个线程调用下面的remove方法,并从列表中删除一个项目。以下代码是否给我一致的行为?
ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>());
void remove(String item)
{
do something; (doesn't work on the list)
list.remove(item);
}
谢谢!
答案 0 :(得分:62)
是的,如果您也在遍历列表,请小心,因为在这种情况下,您需要对其进行同步。来自Javadoc:
当迭代时,用户必须手动同步返回的列表:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
或者,您可以使用CopyOnWriteArrayList
,这对写入速度较慢,但没有此问题。
答案 1 :(得分:23)
只要你不要求“删除”方法是原子的,这应该没问题。
换句话说,如果“执行某事”检查项目在列表中出现多次,那么当您到达下一行时,该检查的结果可能会出错。
另外,请确保在迭代时在列表上进行同步:
synchronized(list) {
for (Object o : list) {}
}
如Peter Lawrey所述,CopyOnWriteArrayList可以让您的生活更轻松,并可在高度并发的环境中提供更好的表现。
答案 2 :(得分:11)
来自Collections#synchronizedList(List)
javadoc
返回由指定的支持的同步(线程安全)列表 名单。为了保证串行访问,至关重要的是 完成后备列表的所有访问权限 通过返回的列表...当迭代时,用户必须手动同步返回的列表。不遵循此建议可能会导致非确定性行为。
答案 3 :(得分:2)
列表可能存在2个不同的问题:
1)如果在迭代中进行修改,即使在单线程环境中,您将具有ConcurrentModificationException,如下面的示例所示:
List<String> list = new ArrayList<String>();
for (int i=0;i<5;i++)
list.add("Hello "+i);
for(String msg:list)
list.remove(msg);
所以,为了避免这个问题,你可以这样做:
for(int i=list.size()-1;i>=0;i--)
list.remove(i);
2)第二个问题可能是多线程环境。如上所述,您可以使用synchronized(list)来避免异常。
答案 4 :(得分:0)
它将为添加/删除操作提供一致的行为。但是在迭代时你必须明确地同步。 Refer this link
答案 5 :(得分:0)
是的,它会正常工作,因为您有synchronized
列表。我建议你使用CopyOnWriteArrayList
。
CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>());
void remove(String item)
{
do something; (doesn't work on the list)
cpList..remove(item);
}
答案 6 :(得分:-4)
synchronized(list) {
for (Object o : list) {}
}