[英]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.