2016-02-02 3 views
1

в классе Я эти 2 метода:Неясная ConcurrentModificationException на отдельных списках

public void notifyResult(List<Road> result) { 
    ArrayList<RoadOverlay> tempRoads = new ArrayList<>(); 

    for(Road road:result){ 
    // Computes and stores the overlays 
    // ... 
     tempRoads.add(new RoadOverlay()); 
    } 
    //switch field when update is done 
    this.positions = tempRoads; 
    } 
} 

private void drawRoadsVO(GL gl) { 
    // keep a reference on the current instance of the field 
    // to avoid concurrent modification in notifyResult 
    ArrayList<RoadOverlay> positionsCopy = this.positions; 
    int vertexCount = 0; 
    for (RoadOverlay road : positionsCopy) { //ConcurrentModificationException here 
      // ... 
     } 
} 

Оба метода проложены в разных потоках. Внутри рендеринга я не делаю никаких изменений в списке, и, насколько я понимаю, я работаю над отдельными списками, так как это может привести к CME? Я борюсь за это, и любой ключ приветствуется. Насколько это возможно, я стараюсь избежать штрафа за использование синхронизации.

С уважением

Отредактировано комментарий в коде

+0

'// работа на копии, чтобы избежать одновременного modification' Вы не копировать список. У вас есть только две ссылки, указывающие на один и тот же экземпляр. –

+0

Я знаю, что это не мелкая копия, но она должна была нести обход в одном экземпляре. Вы думаете, что это бесполезно? – raggnic

+0

Проблема в том, что, как вы сказали, ваши методы работают на отдельных потоках. Когда вы работаете в одном экземпляре, один поток может изменить список, пока вы читаете его в 'drawRoadsVO' (вот почему CME выбрасывается). Таким образом, либо вам нужно сделать глубокую копию перед чтением, либо использовать структуру данных, защищенную потоком. –

ответ

1

Это, как правило, лучше, чтобы сделать полную копию списка

ArrayList<RoadOverlay> positionsCopy = new ArrayList<Integer>(this.positions); 

Что касается ConcurrentModificationException, ваш код выглядит нормально, может быть вы изменяете текущий this.positions в некоторых других методах класса? Обратите внимание, что переменная this.positions должна быть объявлена ​​как volatile.

Вот next() метод ArrayList итератора

public E next() { 
    checkForComodification(); 
    int i = cursor; 
    if (i >= size) 
     throw new NoSuchElementException(); 
    Object[] elementData = ArrayList.this.elementData; 
    if (i >= elementData.length) 
     throw new ConcurrentModificationException(); 
    cursor = i + 1; 
    return (E) elementData[lastRet = i]; 
} 

final void checkForComodification() { 
    if (modCount != expectedModCount) 
     throw new ConcurrentModificationException(); 
} 

ConcurrentModificationException может быть брошено только в том случае, то Листом elementData структурно модифицированного

Структурные изменения являются те, которые изменяют размер списка, или иным образом нарушить его таким образом, что выполняемые итерации могут давать неверные результаты.

+0

Да, я знаю, что я должен предпочесть синхронизированную глубокую копию, но этот код отображает дорожный слой из OpenstreetMap с большим количеством объектов, и я охочусь за каждым хитом производительности. Нет другой темы или метода, изменяющих коллекцию. Я попытаюсь установить его волатильным, в случае, если jvm сделает странные вещи за занавеской. – raggnic

+0

Хм, сейчас я не могу себе представить, как «volatile» мог это исправить. Где в классе 'ArrayList.Itr' CME выбрасывается? Не могли бы вы разместить голову трассировки стека, пожалуйста, – dezhik

+0

Вы правы, ничего не меняет. вот трассировка стека: 'java.util.ConcurrentModificationException \t at java.util.ArrayList $ Itr.checkForComodification (Неизвестный источник) \t at java.util.ArrayList $ Itr.next (Неизвестный источник) \t at org.mycompany.RoadProvider.drawRoadsVO [...] ' – raggnic

1

проблема внутри drawRoadsVO метод ваши позиции varCopy на самом деле не копия, а ссылка на тот же объект this.positions.

Для того, чтобы сделать фактическую копию вы должны сделать

ArrayList<RoadOverlay> positionsCopy = new ArrayList(this.positions); 
Смежные вопросы