簡體   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