[英]Concurrent Modification Exception in LinkedList
我正在寻找一种建立有限链接列表的好方法。 如果链接列表为“完整”,则第一个元素将被删除,而新元素将被添加。 因此,我始终具有“最新”“限制大小”元素。
这是通过以下方式实现的:
private int maxSize;
public LimitedLinkedList(int maxSize) {
this.maxSize = maxSize;
}
@Override
public synchronized boolean add(E object) {
boolean success = super.add(object);
while (this.size() >= maxSize) {
removeFirst();
}
return success;
}
现在,我遇到以下问题:我需要计算链表的平均值。 此时此刻,我随机获得并发修改异常或索引越界异常。 我的平均方法:
public synchronized static double movingAverage(
LinkedList<AverageObject> valueList) {
if (valueList.isEmpty()) {
return 0;
}
double sum = 0;
int m = 0;
for (int i = 0; i < valueList.size(); i++) {
AverageObject object= valueList.get(i);
sum += object.value;
m++;
}
sum = (m != 0) ? sum / m : sum;
return sum;
}
您知道避免并发修改异常的好方法吗?
我唯一的想法是,每次更改列表时都要计算平均值,所以当我想要平均值时,不必遍历该平均值。
并发修改问题实际上与您要add
的修改无关。 如果您在计算平均值时添加了元素,也会在常规LinkedList
发生。 您显示的代码根本无法生成ConcurrentModificationException
也是ConcurrentModificationException
的。 (但它可能会超出范围……)
您在此处遇到问题的最可能原因是您的add
和movingAverage
方法未正确同步:
synchronized
实例方法锁定目标对象。 即列表实例。 static synchronized
方法将Class
对象锁定为该方法的声明类; 即声明您的movingAverage
方法的类。 如果两个线程不锁定同一对象,则它们将不会同步,并且您将不会互相排斥。 这意味着add
和movingAverage
可能会同时读取和更新同一列表...导致异常(或更糟)。
避免这些问题的一种方法可能是将movingAverage
方法更改为:
public static double movingAverage(
LinkedList<AverageObject> valueList) {
synchronized (valueList) {
...
}
}
甚至这个:
public synchronized doubkle movingAverage() {
...
}
但是,这都是零碎的。 更好的方法可能是在更高级别进行同步,或者使用避免需要显式同步的“并发”数据结构。
在您的代码示例中,您同步了movingAverage方法,这意味着对静态方法的访问是线程安全的。 但是,您的列表作为传递给它的参数却没有。 在您通过另一个调用列表的add方法的对象检查平均值时,仍可以同时修改它。 如果您的同步movingAverage()方法位于LimitedLinkedList对象中,则该操作对于add方法而言将是线程安全的。
使用synchronizedList通过Collections.synchronizedList
,并按照指示的javadoc迭代。
仅供参考,有一个ConcurrentRunningAverage已签入GitHub,您可以将其用作指南。 它扩展了BasicRunningAverge 。
尝试这样的事情(仅用于优化代码,它也可能解决您的并发修改异常):
public class LimitedLinkedList extends LinkedList<AverageObject>{
private int maxSize;
private int sum = 0;
public LimitedLinkedList(int maxSize) {
this.maxSize = maxSize;
}
@Override
public synchronized boolean add(AverageObject object) {
sum = sum + object.value;
boolean success = super.add(object);
while (this.size() >= maxSize) {
sum = sum - getFirst().value;
removeFirst();
}
return success;
}
public synchronized double movingAverage(int sum, int length) {
double avegage = (sum != 0) ? sum / length : sum;
return sum;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.