在通过

时间:2018-05-21 14:02:05

标签: java arraylist linked-list hashmap

我目前正在制作游戏并编辑/删除/添加我的所有实体我有一个数组列表。每个帧(每秒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 :(得分:1)

  

还是因为我的列表不是“线程安全”?

是的,如果renderupdate可以在不同的主题上同时运行。

  

这会是如何解决它的?

不,仍然是同样的问题,你会尝试在迭代时删除。

无论

  1. 构建一个只包含您要保留的条目的新列表,然后将其作为list交换(更新对象引用是原子的),或

  2. render上同步updatelist方法的相关部分。

  3. 这是#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();
        }
    }
    

    (再次将循环反转。)

    有关the Java synchronization tutorial中的同步的更多信息。

    附注:您可能还需要检查removeList的迭代和更新。