удаление объекта из списка во время его итерации - PullRequest
0 голосов
/ 21 мая 2018

Я сейчас работаю над игрой, и для редактирования / удаления / добавления всех моих сущностей у меня есть массив List.Каждый кадр (60x в секунду) все в списке обновляется и отображается.Когда я призываю к добавлению или удалению объекта (в методе обновления сущностей), я получаю сообщение об ошибке в «Thread-2».Проведя небольшое исследование, я обнаружил, что редактировать список во время его повторения некорректно.Это проблема, с которой я сейчас сталкиваюсь?или это потому, что мой список не является "потокобезопасным"?

Метод рендеринга:

public void render(Graphics g){
     for(Entity entity: list){
          entity.render(g);
      }
 }

Метод обновления:

public void update(){
     for(Entity entity: list){
          entity.update();
      }
 }

Если проблема в том,что я редактирую список во время его обновления, будет ли это как исправить это?:

public void update(){
     for(Entity entity: list){
          entity.update();
      }

     for(Entity entity: removeList){
          list.remove(entity);
      }
      removeList.clear();
 }

1 Ответ

0 голосов
/ 21 мая 2018

или это потому, что мой список не является "потокобезопасным"?

Да, если render и update могут работать одновременно в разных потоках.

это будет, как это исправить?

Нет, все та же проблема, которую вы попытаетесь устранить во время итерации.

Либо

  1. Создайте новый список, содержащий только те записи, которые вы хотите сохранить, а затем поменяйте его местами как list (обновление ссылки на объект атомарное) или

  2. Синхронизируйте соответствующие части ваших render и update методов на list.

Вот пример грубый для # 1:

public void update(){

    List newList = new AppropriateListType(list);
    for (Entity entity : removeList){
        newList.remove(entity);
    }
    removeList.clear(); // Or removeList = new AppropriateListType();
    list = newList;

    for (Entity entity: list) {
        entity.update();
    }
}

(Обратите внимание, что я изменил порядок этих двух циклов; предположительно, мало смысла в обновлении сущности, которую вы собираетесь удалить.)

Это работает, потому чтоничто не может попытаться перебрать новый список, пока мы его модифицируем, потому что, пока мы не сделаем list = newList, новый список будет полностью закрыт для этого конкретного выполнения метода update.Как только мы сделаем list = newList, он будет на объекте, поэтому другой код попытается использовать его.

И грубый пример # 2:

public void update(){
    synchronized (list) {
        for (Entity entity: removeList){
            list.remove(entity);
        }
    }
    removeList.clear();

    for (Entity entity: list) {
        // This is probably fine depending on how `render` and `update` work
        // but you *may* need to `synchronize` on `entity` (here and in `render`
        // depending on how `render` and `update` work
        entity.update();
    }
}

(Опять с обратными циклами.)

Подробнее о синхронизации в учебное пособие по синхронизации Java .


Примечание: возможно, вам потребуетсячтобы проверить итерацию и обновления до removeList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...