Reputation:
I am currently working on a game and to edit/remove/add all of my entities I have an array List. Every single frame(60x per second) everything in the list is updated, and rendered. When I call for an Object to be added or removed (in the entities update method)I receive an error in "Thread-2". With some quick research I discovered that it is incorrect to edit a list while it is being iterated. Is this the problem I am currently experiencing? or is it because my list isn't "thread safe"?
Render method:
public void render(Graphics g){
for(Entity entity: list){
entity.render(g);
}
}
Update method:
public void update(){
for(Entity entity: list){
entity.update();
}
}
If my problem is the fact that I am editing a list while it is being updated would this be how to fix it?:
public void update(){
for(Entity entity: list){
entity.update();
}
for(Entity entity: removeList){
list.remove(entity);
}
removeList.clear();
}
Upvotes: 0
Views: 80
Reputation: 1074949
or is it because my list isn't "thread safe"?
Yes, if render
and update
can run at the same time on different threads.
would this be how to fix it?
No, still the same problem, you'll try to remove while iterating.
Either
Build a new list with only the entries you want to keep, and then swap it in as list
(updating an object reference is atomic), or
Synchronize the relevant parts of your render
and update
methods on list
.
Here's an rough example of #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();
}
}
(Note I reversed the order of those two loops; little point in updating an entity you're about to remove, presumably.)
That works because nothing can try to iterate the new list while we're modifying it, because until we do list = newList
, the new list is entirely private to this specific execution of the update
method. Once we do list = newList
, it's on the object, so other code will try to use it.
And a rough example of #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();
}
}
(Again with the loops reversed.)
More about synchronization in the Java synchronization tutorial.
Side note: You may need to check your iteration of and updates to removeList
as well.
Upvotes: 1