From a personal example. I was making a space invaders game for personal growing and it used multiple Thread
s. One Thread
handled the rendering and another handled game logic. This is before I had a firm grasp on concurrency and how to properly implement it in Java.
Anyways, I had an ArrayList<Laser>
that held all of the Laser
s in the system at any given frame in the game (or so I thought). Because of the nature of space invaders, that List
was extremely dynamic. It was constantly being added to as new Laser
s spawned and removed from as they either went off the map or collided with an entity.
This worked all well and good, except every so often I would receive a ConcurrentModificationException
. It took me a long time to figure out exactly what was going on. It turns out that the rendering Thread
was on rare occasions being caught iterating through the List<Laser>
at the same time as the game logic Thread
was either adding new Laser
s or removing them.
This is because when Thread
1 gets the pointer to the List
objects spot in memory, it's almost as though it is in the process of "operating" on that memory block. Thread
2 comes along and grabs that same pointer unaware that the object is already on the "operating table" being modified by Thread
1 and it tries to go about doing what it intended, only to find that what Thread
2 thought it really knew about the object was incorrect due to Thread
1's modifications. This is what ends up throwing the ConcurrentModificationException
.
This can be solved several different ways. I think the most efficient and safe way to solve this now is with Java 8's Stream
API (If done properly, it will ensure true parallelism), or you can use synchronized
blocks (I think they came into existence in Java 5). With synchronized
blocks, the current Thread
that is looking at the object will essentially lock it, not allowing any other Thread
s to even observe the object. Once the Thread
is done, it releases the object for the next Thread
to operate on it.
Here is two examples of how to use synchronized
:
public synchronized void xamp1(List<Laser> lasers){
for(Laser l:lasers){
//code to observe or modify
}
}
public void xamp2(List<Laser> lasers){
synchronized(lasers){
for(Laser l:lasers){
//code to observe or modify
}
}
}