我目前正在开发一个游戏,要编辑/删除/添加我的所有实体,我有一个数组列表。每一帧(每秒 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();
}
还是因为我的列表不是"线程安全"?
是的,如果render
和update
可以在不同的线程上同时运行。
这是如何解决它吗?
不,仍然是相同的问题,您将在迭代时尝试删除。
也
-
仅包含要保留的条目构建一个新列表,然后将其交换为
list
(更新对象引用是原子的(,或者 -
在
list
上同步render
和update
方法的相关部分。
下面是 #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
的迭代和更新。