public void update(double delta)
This method sounds like one that's being called by an engine of some sort, which is almost certainly in another thread.
for (Entity e : entities) {
g.fillRect(x, y, w, h);
}
This is running in your swing thread, which is separate.
When you have a few number of entities it is likely that this operation may complete atomically. When you have a much larger number of entities, you have a much higher chance of swapping into another thread to do work in the middle of drawing the entities.
The fix(I'm assuming zombies and survivors are entities):
synchronized(entities)
{
for (Survivor s : toRemove) {
survivors.remove(s);
}
for (Zombie z : toAdd) {
zombies.add(z);
}
}
And in your paint:
synchronized(entities)
{
for (Entity e : entities) {
g.fillRect(x, y, w, h);
}
}
This will ensure that only 1 thread can be in one of the synchronized blocks at a time, forcing them to happen separate from eachother
EDIT: This has a possibility of painting a frame after a collision has occurred. If your frame rate is high enough this will be completely unnoticeable. If you do start to notice it, then you may need to do a little bit more work so that once an update starts, a paint will not start until completely done.