2013-05-14 56 views
0

我正在寻找一种很好的方法来构建一个有限的链接列表。如果链表是“满”,则第一个元素将被删除,新的元素将被添加。所以我总是有“最新”的“极限尺寸”元素。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; 
} 

你知道避免同时修改异常的好方法吗?

我唯一的想法是,计算平均值,每次列表中被改变,所以我没有来遍历它,当我想拥有的平均水平。

回答

5

的并发修改问题其实没什么用您的修改做add。如果您在计算平均值时添加了一个元素,它也会与常规的LinkedList一起发生。您所展示的代码根本无法生成ConcurrentModificationException也不值得。 (但它可能发出的越界例外...)

你在这里有问题,最有可能的原因是你addmovingAverage方法不正确同步:

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

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

一种方式是到movingAverage方法改成这样:

public static double movingAverage(
    LinkedList<AverageObject> valueList) { 
    synchronized (valueList) { 
     ... 
    } 
} 

,甚至这样的:

public synchronized doubkle movingAverage() { 
    ... 
} 

然而,这一切零碎。更好的方法可能是在更高层次上进行同步,或者使用“并发”数据结构来避免显式同步。

+0

非常感谢您!非常有用的回答:) – Frame91 2013-05-14 13:06:42

2

在你的代码示例,你同步的movingAverage方法,这意味着访问静态方法是线程安全的。但是,作为传递给它的参数的列表不是。当您通过另一个调用列表的add方法的对象检查平均值时,它仍然可以被修改。如果同步的movingAverage()方法将存在于LimitedLinkedList对象中,那么该操作对于add方法将是线程安全的。

1

尝试是这样的(仅用于优化你的代码,它也可以解决你的并发修改除外):

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; 
} 

}