Java 为什么即使在同步列表时也会出现ConcurrentModificationException?

Java 为什么即使在同步列表时也会出现ConcurrentModificationException?,java,concurrentmodification,Java,Concurrentmodification,我有Android多线程应用程序 两个或多个触发器可能运行代码的同一部分 我有一个物品清单 我让它通过集合进行同步。synchronizedList private List<WmGroupItemSample> mGroupItemSampleList; mGroupItemSampleList = new ArrayList<WmGroupItemSample>(); mGroupItemSampleList = Collections.synchronizedLi

我有Android多线程应用程序

两个或多个触发器可能运行代码的同一部分

我有一个物品清单

我让它通过
集合进行同步。synchronizedList

private List<WmGroupItemSample> mGroupItemSampleList;

mGroupItemSampleList = new ArrayList<WmGroupItemSample>();
mGroupItemSampleList = Collections.synchronizedList(mGroupItemSampleList);

  • 这种流动合法吗
  • 我是否需要创建副本并在副本上运行排序
  • 为什么
    Collections.synchronizedList
    不能阻止此异常
[编辑]

GroupItemSampleComparator

公共类GroupItemSampleComparator实现java.util.Comparator{
公共GroupItemSampleComparator(){
超级();
}
公共整数比较(WmGroupItemSample s1、WmGroupItemSample s2){
返回((s2.getStartDate()-s1.getStartDate())>0)?(-1):(1);
}
}

谢谢,

此异常不仅仅发生在多线程环境中。例如,如果在迭代过程中对列表进行迭代并删除某个元素,则可能会发生此异常(取决于删除该元素的方式)。

集合。synchronizedList(list)
返回一个同步列表,这意味着列表的方法将被同步(同时只能运行其中一个)

但是,这并不意味着当其他人(或者您)正在使用列表的迭代器对列表进行迭代时,您不能调用列表的方法(迭代器()返回的迭代器不同步)。
synchronizedList()
不保护您获得
ConcurrentModificationException
,如果有人在列表上迭代,并且该列表以迭代器方法以外的任何其他方式修改

编辑:

另外,您的
GroupItemSampleComparator
错误,如果传递的2个对象被其
equals()
方法视为相等,则它必须返回
0
。请尝试此操作(假设
getStartDate()
返回
long
):

public int比较(WmGroupItemSample s1、WmGroupItemSample s2){
long diff=s2.getStartDate()-s1.getStartDate();
返回差值>0?-1:diff<0?1:0;
}

基本问题是同步列表没有以有用的方式同步

问题是,虽然它的方法是同步的,但像移动应该是原子的元素这样的操作是不同步的,因为移动所需的单独调用没有同步在一起。这意味着其他线程可以在单独的方法调用之间进行。因此,同步的集合现在基本上被弃用

尽管存在此缺陷,但如果在线程排序时让另一个线程添加元素,则会出现此异常,因为排序会迭代,并且在迭代期间更改列表会导致异常

幸运的是,得益于
java.util.concurrent
包,JDK有了新的集合类,这些类具有工业级的(并且非常有用)同步


将您的列表替换为,不要“同步”它,您就可以开始了。

也许这会有所帮助-看不到所有代码,并且有机会访问列表。引用Javadoc中的
synchronizedList(列表列表)

返回由指定列表支持的同步(线程安全)列表。为了保证串行访问,必须通过返回的列表完成对支持列表的所有访问

用户在对返回的列表进行迭代时,必须手动同步该列表:

List list = Collections.synchronizedList(new ArrayList());
  ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

那么,这个列表上的所有迭代都是以这种方式保护的吗?

这个异常可以在没有任何[附加]的情况下复制线程-因此,同步没有关系。你使用的是哪种Java版本?我看过一些Collections.Java,但第1895行没有排序。伙计们,为什么你要关注比较器?@pavel:我记得阅读原始问题时,好像没有多个线程。这就是为什么每个人都要求使用比较器。请阅读在编辑版本中,这似乎只是“正常”并发修改。我知道可能是重复的,但为什么异常会将我指向集合。排序?我可以理解排序过程会删除和附加用于排序目标的项。我如何才能消除这种情况?@fessy您能提供您的
GroupItemSampleComparator
?添加了GroupItemSampleComparator类您知道在这里s case我不能使用集合。sort它可以工作,但问题是“迭代器不会反映自迭代器创建以来对列表的添加、删除或更改”
java.util.ConcurrentModificationException
       at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:62)
       at java.util.Collections.sort(Collections.java:1895)
public class GroupItemSampleComparator implements java.util.Comparator<WmGroupItemSample> {

    public GroupItemSampleComparator() {
        super();        
    }

    public int compare(WmGroupItemSample s1, WmGroupItemSample s2) {
       return ( (s2.getStartDate() - s1.getStartDate()) > 0 ) ? (-1) : (1);
    }
}
public int compare(WmGroupItemSample s1, WmGroupItemSample s2) {
    long diff = s2.getStartDate() - s1.getStartDate();
    return diff > 0 ? -1 : diff < 0 ? 1 : 0;
}
List list = Collections.synchronizedList(new ArrayList());
  ...
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}