ConcurrentModificationException when updating sprite images - java

I keep getting a ConcurrentModificationException when running my game which utilizes multithreading to create new sprites and move them. The main problem appears to happen with the creation and/or movement of "Fireballs".
I've been able to run my program successfully with no exceptions appearing by commenting out the createNewFireballs method. However, whenever I do utilize the createNewFireballs method, the error commonly appears whenever I call a function that updates the image of the Fireball Sprite (and doesn't ever happen for any other type of sprite.) I was wondering if anyone could help me locate the source of my problem and potentially solve the issue.
public synchronized void createNewFireball() {
new Thread(new Runnable() {
public void run() {
while (gameNotPaused && hero.isNotDead()) {
fireball = new Fireball(dragon.getX(), dragon.getY());
fireballs.add(fireball);
try
{
Thread.sleep(100); //Waits for .1 second
}
catch(InterruptedException e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}).start();
}
//The problem commonly occurs in the update method,
//specifically the line "FireballIter.next().updateImage(g);"
public synchronized void update(Graphics g) {
Iterator<Sprite> FireballIter = fireballs.iterator();
Iterator<Sprite> arrowIter = arrows.iterator();
while (arrowIter.hasNext()) {
arrowIter.next().updateImage(g);
}
Iterator<Sprite> iterator = sprites.iterator();
while (iterator.hasNext()) {
iterator.next().updateImage(g);
}
while (FireballIter.hasNext()) {
FireballIter.next().updateImage(g);
}
}
//Although sometimes it occurs as a result of updateScene, which is
//called in another method which moves all the "projectile" sprites
public synchronized void updateScene(int width, int height) {
Iterator<Sprite> arrowIter = arrows.iterator();
while(arrowIter.hasNext()) {
Sprite spriteObject = arrowIter.next();
((Arrow) spriteObject).updateState();
if (spriteObject.overlaps(dragon, 350, 350)) {
dragon.arrowHit();
System.out.printf("Dragon was hit at %d, %d%n, while arrow was at %d,%d%n", dragon.getX(), dragon.getY(), spriteObject.getX(), spriteObject.getY());
arrowIter.remove();
}
}
Iterator<Sprite> fireballIter = fireballs.iterator();
while(fireballIter.hasNext()) {
Sprite spriteObject = fireballIter.next();
((Fireball) spriteObject).updateState();
}
}
#Override
public synchronized void run() {
while (model.getGameNotPaused()) {
model.updateScene(view.getWidth(), view.getHeight());
view.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
JOptionPane.showMessageDialog(null, "Press R to resume game.");
}
}
}

Making createNewFireball synchronized does nothing useful: the synchronization only applies to the execution of that method, not the runnable executed by the thread (which is good, because otherwise none of the other methods would be able to execute until the while loop finished).
Put the fireballs.add into a synchronized block, taking care to ensure you are synchronizing on the right thing:
If you simply use synchronized (this), you would be synchronizing on the Runnable.
Instead, use synchronized (TheContainingClass.this) (where TheContainingClass is the name of the class containing these methods).

Assuming your fireballs is an ArrayList<Fireball>, you could also consider switching it to CopyOnWriteArrayList , a thread-safe variant of ArrayList

Related

Wait until the thread finish

I have a function that has inside thread that do something
public static void animate(int column,Image image)
{
new Thread(new Runnable() {
public void run() {
try {
/* Code */
repaint();
Thread.sleep(500);
repaint();
} catch (InterruptedException ex) {
}
}
}).start();
}
The animation function I summon in the updateBoard function and after this do i++.
I want to make the function animate not continue to I++ until the thread end
Inside animate fucntion i used repaint() function from swing, When i try to use .join() its block repaint() thread.
public static void updateBoard(int column, Image image) {
int i = 0;
animate(column,image);
i++;
}
Like this:
Thread t = new Thread(new Runnable(){...});
t.start();
t.join();
However, this is kind of pointless. If you are going to start a thread and immediately block waiting for it to finish you are NOT going to get any parallelism. You may as well just call the Runnable::run method in the current thread ... and avoid the (not insignificant!) overhead of creating / starting a thread.
You have a already existing thread executing updateBoard() method. Let this thread be T1.
You invoke animate() and create another thread, let this thread be T2. Now as per your question, you want to have T1 not run further until T2 completes the execution.
Thread.java defines a method join(), it allows one thread to wait for the completion of another. In your code it can be done like this.
static Thread animationThread = new Thread(new Runnable() {
public void run() {
try {
/* Code */
Thread.sleep(500);
} catch (InterruptedException ex) {}
}
});
public static void updateBoard(int column, Image image) {
int i = 0;
animate(column,image);
animationThread.join(); // this will make the thread executing updateBoard to wait until the completion of animationThread.
i++;
}
public static void animate(int column,Image image){
animationThread .start();
}
But now every thing runs one after the other, there is no use of having two threads in this case. This is similar to
public static void updateBoard(int column, Image image) {
int i = 0;
animate(column,image);
i++;
}
public static void animate(int column,Image image){
try {
/* Code */
Thread.sleep(500);
} catch (InterruptedException ex) {}
}
In this case also until unless animate method completes (without 2nd thread), i++ will not be executed. Hence for the use case in your question having a separate thread for animate does not make sense, it only adds to the overhead of creating a separate thread and context switching. Although having a separate thread for animation seems a good idea but for that you got to restructure the program you have so as the logic is based on parallel execution so as having multiple threads makes sense.

how to decide the looping condition for wait() in Java

I am understanding wait() in Java in regards to multithreaded, and as per the documentation, wait() should always be in a loop.
I have difficult in understanding what is the condition we have to give in the loop. Typically, I have seen:
synchornized(obj) {
while(some_condition) {
obj.wait();
}
// some other code
}
I am having difficulty in understanding the "condition" which is used in the loop within which we are keeping wait().
I tried to implement a scenario in which I created two different threads (two different classes implementing Runnable interface), for printing Odd and Even numbers, like: 1 ,2 ,3,4,5,6...
As this is inter-thread communication and we need synchronization, I am having difficulty in relating what is the condition on which I have to keep wait() in loop for these two different threads.
Any clues as to how to decipher this (the condition we keep in loop) greatly appreciated.
Here, maybe this few lines will push you in the right direction, as a follow up to my previous comments.
class LastPrintedMonitor {
public boolean wasLastEven = false;
}
class PrinterOdd implements Runnable {
LastPrintedMonitor monitor;
public PrinterOdd(LastPrintedMonitor monitor) {
this.monitor = monitor;
}
#Override
public void run() {
for (int i = 2; i < 40; i += 2) {
synchronized (monitor) {
while (!monitor.wasLastEven) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
monitor.wasLastEven = false;
monitor.notifyAll();
}
}
}
}
class PrinterEven implements Runnable {
LastPrintedMonitor monitor;
public PrinterEven(LastPrintedMonitor monitor) {
this.monitor = monitor;
}
#Override
public void run() {
for (int i = 1; i < 40; i += 2) {
synchronized (monitor) {
while (monitor.wasLastEven) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(i);
monitor.wasLastEven = true;
monitor.notifyAll();
}
}
}
}
public class EvenOddPrinterDemo {
public static void main(String[] args) {
LastPrintedMonitor monitor = new LastPrintedMonitor();
Thread odd = new Thread(new PrinterOdd(monitor));
Thread even = new Thread(new PrinterEven(monitor));
odd.start();
even.start();
try {
odd.join();
even.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done!");
}
}
You mentioned two classes so their synchronized methods will not be synchronized to each other. That's why we synchronized on monitor, as there has to be something that those two objects share to make them "hear" each other.
The looping condition should check whether the execution(threads of the current class) need to be temporarily paused.
Taking an example of famous producer-consumer problem, where in the producer will somehow looks like
synchronized(mySharedObj)
{
while(mySharedObj.length==maxSize)
{
mySharedObj.wait();
}
}
If there are n number of Producer Threads on mySharedObj, all will be waiting when the shared resource(mySharedObj) has reached its limit.

Why we use a flag to stop a thread?

When I tried to figure out how to stop a thread in a program with multiple threads,
I was suggested to call a method which actually sets a flag to tell that thread stop doing real works,like this:
public class ThreadTobeTerminated implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
private volatile boolean running = true;
public void terminate() {
running = false;
}
#Override
public void run() {
while (running) {
try {
LOGGER.debug("Doing some real work ,like Counting...");
for(int i=0;i<100;i++){}
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
}
}
when I want to stop this tread ,I'll call threadInstance.terminate();.
Don't I need to literally stop this thread ?
Why I should leave this thread to do some useless work (method run called ,test the flag running==false then return)? I mean :this is a waste of time ,isn't it?
When the execution scope goes beyond the run() method, the thread stops, so the moment that the while loop is broken, the thread will stop.
This would also allow you to do some clean up if the situation requires it:
public void run() {
while (running) {
try {
LOGGER.debug("Doing some real work ,like Counting...");
for(int i=0;i<100;i++){}
} catch (InterruptedException e) {
LOGGER.error("Exception", e);
running = false;
}
}
//Clean up
}
The above approach allows you some control over how is the thread stops and what happens after as opposed to potentially just kill it, which could cause all kinds of problems.

How should I properly block access from other threads to this object?

I'm doing this little exercise myself trying to understand how should I work with concurrency and threads.
It happens that sometimes I have an object that I can't modify its source code and that is not thread-safe, so I want it to be accessed just by one thread.
In this example that thirdparty object that I can't touch is called Holdeable. What I do is trying to wrap it into a class called Holder that has synchronized methods, and I expect that by doing it only one thread can access that Holdeable object. At sometime I null the reference to the Holdeable object and I want it properly done so when the other thread evaluates mHolder.getHoldeable()==null is true, and avoids entering the code that can cause a NullPointerException.
My last attempt included a synchronized block, which is this:
class Holder {
Holdeable mHoldeable;
public synchronized void setHoldeable(Holdeable holdeable) { mHoldeable = holdeable; }
public synchronized Holdeable getHoldeable() { return mHoldeable; }
}
class Holdeable { // Cannot be modified, that would be to cheat :D
public int someValue;
}
public class MainClass {
private static Holder mHolder;
public static void main(String[] args) {
try {
Holdeable holdeable = new Holdeable();
mHolder = new Holder();
mHolder.setHoldeable(holdeable);
new Thread(new Runnable() {
#Override
public void run() {
try {
while(true) {
synchronized(mHolder) {
if(mHolder.getHoldeable() != null) {
Thread.sleep(23);
System.out.println(mHolder.getHoldeable().someValue);
} else {
System.out.println("No holder!");
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
mHolder.getHoldeable().someValue = 2;
Thread.sleep(1500);
mHolder.getHoldeable().someValue = 3;
Thread.sleep(500);
mHolder.setHoldeable(null);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This example avoids throwing a NullPointerException, but as you can see, it just takes a lot to execute with so much locking. I'm struggling with this while I read the book "The art of concurrency" to see if I finally get it.
What do you think?
Your code is not thread-safe. You have two levels of locking:
Holder's methods are synchronized;
you synchronize on the Holder instance.
Point 1. doesn't give you enough synchronization because it covers only fetching holdeable and not accessing its properties;
Point 2. doesn't give you any synchronization at all because you are acquiring the lock only in one thread.
I suggest you use only point 2. and apply it consistently.
BTW your program takes so long to execute because it calls Thread.sleep. The performance of locking is way too high for you to be able to notice it without involving tight loops repeating at least hundreds of thousands of times.
public class Holder {
final Holdeable mHoldeable;
Holder(Holdeable holdeable) {
this.mHoldeable = Objects.requireNonNull(holdeable, "Holdeable cannot be null");
}
Holdeable get() {
return mHoldeable;
}
}
Using this construct will make your life so much easier. And as you might have noticed: it as well removes the need to synchronize. And if I ever write a book, that would be in it on page one. ;)
Threading and synchronization is done almost 100% on architectural level, adding some synchronized blocks is just a backup/quick & dirty solution.

IllegalArgumentException in unlockCanvasAndPost (android live wallpaper)

I've created my first live wallpaper implementing drawing in a separate thread. So now I have a WallpaperService and my WallpaperPainter who does the job. The problem is that I getting a IllegalArgumentException in unlockCanvasAndPost method on some of devices (Samsung Note is the one). I've read all recomendations I could find but couldn't fix that bug. Seems like the unlockCanvasAndPost is called when surface is destroyed so canvas is invalid. Here is the essential parts of code:
In wallpaper service:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
super.onSurfaceChanged(holder, format, width, height);
painting.setSurfaceSize(width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
painting.start();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
painting.stopPainting();
while (retry) {
try {
painting.join();
retry = false;
} catch (InterruptedException e) { }
}
super.onSurfaceDestroyed(holder);
}
In the painting thread:
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
public void run() {
this.run = true;
Canvas c = null;
while (run) {
try {
synchronized (this) {
Thread.sleep(50);
c = this.surfaceHolder.lockCanvas();
doDraw(c);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
}
}
// if pause...
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) { }
}
}
}
}
Can anyone give me any clue what I'm doing wrong? I'm new both for Java and Android.
If error is: UnlockAndPost Failed, it means it unlocked no buffer.
After this.surfaceHolder.unlockCanvasAndPost(c);
you can append
this.surfaceHolder.lockCanvas();
(sorry for my poor English proficiency)
When you open the preview of wallpaper, creates the object WallpaperService and further creates an instance of Engine. Then the stream starts drawing wallpaper.
Then, when you click "Set wallpaper" - a new instance of WallpaperService is not created. But he call the onCreateEngine() method, which returns another (second) instance of Engine. Which also runs its own thread.
Now you have two competing thread!!! So they lead to an exception being thrown.
All you need to do to fix the bug - is to write a correct method onCreateEngine().
replace this:
#Override
public Engine onCreateEngine() {
return new SampleEngine();
}
to this:
private SampleEngine engine;
#Override
public Engine onCreateEngine() {
if (engine!=null) {
engine.painting.stopPainting();
engine = null;
}
engine = new SampleEngine();
return engine;
}
I don't see a definitive problem but here are some thoughts.
There is a chance that you unlock a canvas that has not been locked. I would set c = null; at the top of your while loop otherwise the previous value of c would be unlocked the next time through the loop.
while (run) {
Canvas c = null;
...
Your run field should be marked as volatile because it is accessed by multiple threads.
Never call Thread.sleep(...) inside of a synchronized block. That's a very bad practice since it blocks other threads unnecessarily.
Make sure you at least log your exceptions. Be extremely careful about catch (Exception e) {}. All that does is mask your problems.
There isn't much point in doing the join() inside a while loop. If your thread gets interrupted you should interrupt the painting thread and quit.
Since you are both sleeping and waiting, it would make more sense to remove the sleep and do something like:
try {
synchronized (this) {
if (wait) {
wait();
else {
wait(50);
}
}
} catch (Exception e) {
e.printStackTrace();
}
I had the same problem with my live wallpaper. On a Nexus 5 emulator it runs fine, but when I run it on a Nexus 10 emulator it crashes the moment the app loads.
I found out that the problem was because the default Skin for the emulator has the wrong resolution. After I changed the Skin to "No Skin" then I don't get the crash anymore.
For more information on how to fix the Skin with wrong resolution, please see:
Android Studio - Tablet emulator not showing correct resolution

Categories