在循环访问对象时从列表中删除该对象



我目前正在开发一个游戏,要编辑/删除/添加我的所有实体,我有一个数组列表。每一帧(每秒 60 倍(列表中的所有内容都会更新和渲染。当我调用要添加或删除的对象(在实体更新方法中(时,我在"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();
}

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

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

这是如何解决它吗?

不,仍然是相同的问题,您将在迭代时尝试删除。

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

  2. list上同步renderupdate方法的相关部分。

下面是 #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的迭代和更新。

相关内容

  • 没有找到相关文章

最新更新