多线程Java同步列表上的getSize()
List<Ball> myObjs = myThreads[threadIndex].getMyObjList();
int initialSize = Collections.synchronizedList(myObjs).size();
抛出ConcurrentModificationException。我也试着把这个放在一个盒子里 同步(myObjs)块,但也不起作用。解决办法是什么?在我使用此列表的其他地方,它都在一个同步(块)中
另外,此错误最终也会产生BrokenBarrierException。(是的,我正在使用循环屏障进行同步)
编辑:以下是堆栈跟踪:
Exception in thread "Thread-3" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1091)
at java.util.ArrayList$SubList.size(ArrayList.java:921)
at java.util.Collections$SynchronizedCollection.size(Collections.java:1573)
at Part2.Animation.processCollisions(MyClass.java:133) // This is the call to size()
编辑:循环看起来像
for (int threadIndex=0; threadIndex < numThreads; threadIndex++) {
List<Ball> myObjs = myThreads[threadIndex].getMyObjList();
int initialSize = Collections.synchronizedList(myObjs).size();
}
不管numThreads是什么,当threadIndex=1时都会发生异常
# 1 楼答案
查看一些
List
类的源代码,我看不出调用size()
将抛出ConcurrentModificationException
的可能性。如果你给我们看一个堆栈跟踪会有帮助的但与此同时,你似乎对
Collections.synchronizedList
的作用有一个基本的误解。它所做的是创建并返回一个列表包装器,以确保同一包装器实例上的操作同步无论如何,它不会阻止线程对底层列表执行非同步操作;i、 e.刚刚包装的列表对象。如果一个线程有底层列表的引用,那么它可以直接访问它,而无需经过包装器。对于同一个基础列表,它也不能使用不同的包装器来同步操作。因此,如果在同一个列表中调用
Collections.synchronizedList
两次,将创建两个不同的包装器,它们彼此不同步因此,实际上
Collections.synchronizedList(myObjs).size()
根本不执行任何有意义的同步。没有其他线程可以获得创建的同步列表包装器,因此没有其他线程可以通过包装器与此同步# 2 楼答案
如果要修改包含2个或以上线程的列表,应该使用
CopyOnWriteArrayList
“该数组在迭代器的生命周期内不会更改,因此不可能发生干扰,并且迭代器保证不会抛出ConcurrentModificationException。”
# 3 楼答案
它是由
subList()
引起的,与同步无关myObjs
是subList()的结果,实际上myObjs是原始列表的视图。如果修改了原始列表,ConcurrentModificationException
将在调用subList.size()
时发生。这是有道理的,视图应该与其原始列表保持一致相反,你可以得到如下子列表: