即使列表同步,为什么会出现ConcurrentModificationException?

sna*_*ggs 8 java concurrentmodification

我有Android多线程应用程序.

两个或更多触发器有可能运行相同的代码部分.

我有一个对象列表.

我让它同步了 Collections.synchronizedList

private List<WmGroupItemSample> mGroupItemSampleList;

mGroupItemSampleList = new ArrayList<WmGroupItemSample>();
mGroupItemSampleList = Collections.synchronizedList(mGroupItemSampleList);
Run Code Online (Sandbox Code Playgroud)

有时我会在线获得Exception:

Collections.sort(mGroupItemSampleList, new GroupItemSampleComparator());
Run Code Online (Sandbox Code Playgroud)
java.util.ConcurrentModificationException
       at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:62)
       at java.util.Collections.sort(Collections.java:1895)
Run Code Online (Sandbox Code Playgroud)
  • 这种流程合法吗?
  • 我是否需要创建副本并在副本上运行排序?
  • 为什么Collections.synchronizedList不阻止此异常?

[编辑]

GroupItemSampleComparator

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢,

Boh*_*ian 14

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

问题是,虽然它的方法是同步的,但是移动元素应该是原子的动作不是,因为移动所需的单独调用不会同步在一起.这意味着其他线程可以介入各个方法调用之间.因此,同步集合现在基本上已被弃用.

尽管有这个缺陷,如果你的线程在排序时有另一个线程添加一个元素,你将得到这个异常,因为sort迭代并在迭代期间更改列表会导致异常.

幸运的是,JDK具有新的Collection类,这些类具有工业强度(和有用的)同步,这是由java.util.concurrent软件包提供的.

用a替换你的列表CopyOnWriteArrayList,不要"同步"它,你会很高兴.


icz*_*cza 9

Collections.synchronizedList(list) 返回一个同步列表,这意味着列表中的方法将被同步(只有其中一个可以同时运行)。

然而,这并不意味着您不能在其他人(或者您)使用其迭代器(返回的迭代器iterator()不同步)迭代列表时调用列表的方法。如果有人正在迭代列表并且它以迭代器的方法以外的任何其他方式修改,synchronizedList()则不会保护您免于获得ConcurrentModificationException

编辑:

你也GroupItemSampleComparator很糟糕,0如果传递的 2 个对象被它们的equals()方法认为是相等的,它必须返回。试试这个(假设getStartDate()返回long):

public int compare(WmGroupItemSample s1, WmGroupItemSample s2) {
    long diff = s2.getStartDate() - s1.getStartDate();
    return diff > 0 ? -1 : diff < 0 ? 1 : 0;
}
Run Code Online (Sandbox Code Playgroud)