繁体   English   中英

LinkedList中的并发修改异常

[英]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的。 (但它可能会超出范围……)

您在此处遇到问题的最可能原因是您的addmovingAverage方法未正确同步:

  • synchronized实例方法锁定目标对象。 即列表实例。
  • static synchronized方法将Class对象锁定为该方法的声明类; 即声明您的movingAverage方法的类。

如果两个线程不锁定同一对象,则它们将不会同步,并且您将不会互相排斥。 这意味着addmovingAverage可能会同时读取和更新同一列表...导致异常(或更糟)。

避免这些问题的一种方法可能是将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM