我目前正在制作游戏并编辑/删除/添加我的所有实体我有一个数组列表。每个帧(每秒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();
}
答案 0 :(得分:1)
还是因为我的列表不是“线程安全”?
是的,如果render
和update
可以在不同的主题上同时运行。
这会是如何解决它的?
不,仍然是同样的问题,你会尝试在迭代时删除。
无论
构建一个只包含您要保留的条目的新列表,然后将其作为list
交换(更新对象引用是原子的),或
在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();
}
}
(再次将循环反转。)
有关the Java synchronization tutorial中的同步的更多信息。
附注:您可能还需要检查removeList
的迭代和更新。