Jump to content
  • Advertisement
Sign in to follow this  
Sirveaux

Java: Thread/paint conflict

This topic is 5465 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a thread for my main game loop that calls repaint() at the end, right before it sleeps. A problem occurs when the painting is not finished and the sleep ends. The player location is changed while in the middle of painting, which causes some jumping around of the display. I have tried this to fix it:
boolean paint_done;
//...
public void paint(Graphics g) {
   paint_done = false;
   // PAINT STUFF
   paint_done = true;
   notifyAll();
}

public void run() {
   //...
   while (!paint_done)
      gameThread.wait();
   // Perform player movement, etc...
}

But, both my wait() and epsecially my notifyAll() throw an IllegalMonitorStateException everytime. I'm not really sure why this is or what I'm doing wrong. Any suggestions would be appreciated.

Share this post


Link to post
Share on other sites
Advertisement
This isn't java specific (haven't worked with threads in java) so i may be totally off here, but in C/C++ when doing threads I can't control when one executes or when the other executes unless I use something like Semaphores (maybe java has an equivalent).

btw, usually a certain order of operations must be achieved in games (update then render) so that paint isn't called all over the place and generally threads would be less efficient so if you can go without them i suggest you do.

HTH

Share this post


Link to post
Share on other sites
Before you can wait() on gameThread, or notifyAll() it, the current thread must 'own the monitor' of the object. In Java, every object is a "monitor", i.e. a synchronization primitive. Attached to the object, in memory, are a few bytes which identify (by pointer - shh! low-level implementation details! fnord fnord!) the thread which is "locking" that object.

Quoting directly from the javadoc for java.lang.Object:

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

# By executing a synchronized instance method of that object.
# By executing the body of a synchronized statement that synchronizes on the object.
# For objects of type Class, by executing a synchronized static method of that class.

Assuming that gameThread is the particular object that you are calling these paint() (indirectly via repaint()) and run() (indirectly via start()) methods on, it should be sufficient to just specify that these methods are synchronized:

public synchronized void paint(Graphics g) {

This causes no problems with overloading, so don't worry about the method signature.

Once your methods are synchronized, the boolean 'paint_done' becomes superfluous. What happens is that at the beginning of a synchronized method, the thread that wants to execute that method must first try to grab the object's monitor (the object that the method is being called on). If it is available, then it will grab it, and start executing code. Otherwise, that thread is blocked (can't do anything) until the monitor is released. Finally, when the thread finishes the method, it will release the monitor (so others can grab it).

So it looks like this:

Thread A starts executing paint().
Thread B tries to execute run(), but can't yet.
Thread A finishes executing paint(). At some later point, the JVM gets thread B to start up, and it sees that the lock is available.
Thread B starts executing run().
Thread A tries to execute paint(), but can't. Oops, run() is in an infinite loop (game loop). Doh. What we need to do is put the synchronization *inside* that loop instead.

So we change it to:

public void run() { // no 'synchronized' here
//...
while (true) {
synchronized(gameThread) {
// do stuff
}
}
}


Now, iterations of the game loop have to take turns with paint() calls. Neither can interrupt the other, they act as nice little atomic chunks.

So at this point you're probably wondering what the notifyAll() and wait() are *good for*, anyway. Well - they're so you can make sure that the threads take turns *evenly*, i.e. you don't have one going a few times in a row and shutting the other out. As it stands right now, you're relying on the JVM to start up whichever thread is blocked when it gets a chance. The wait() is a signal you can send at the end of your synchronized chunk, to queue up for a request to execute again. The notifyAll() is a signal to indicate that you're done, and don't want to execute again, so please let one of the queued-up threads have a chance.

Share this post


Link to post
Share on other sites
its probably worth your time reading some sites on animation in java, they cover this area pretty comprehensively

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!