2013-05-14 54 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; 
} 

}