When to use Thread.sleep over SwingTimer in 2D animation - java

The context in this case is creating a game loop that integrates with the model and updates the view once per frame. Listeners interface with the controller, controller updates the model, repaint() handles the view update from model (on an overridden paintComponent() on a JPanel).
Appropriate answers include "never", haha.
This is a question I would think there is a preferable answer to, so it shouldn't be in violation of the rules.
I'm asking this because the main game loop is a Runnable instance which I'm locking to 60FPS (roughly, at the moment. Few milliseconds of difference as the current render loop is very inexpensive and 1000 / 60 loses a millisecond or two each cycle). Not locking the frame rate via Thread.sleep() causes something like 2.3 billion frames per second (apparently), which understandably thrashes my CPU. Not a problem per say, more of an example why frame-locking is desirable.
However in every single answer I come across, every single comment, the majority of them say "why are you even touching Thread.sleep() you don't want the EDT to sleep". Which is understandable if you have flaws in your loop that cause non-responsiveness, but this isn't the case in the applications I've put together yet. I've read all of the associated Event Dispatch Thread documentation, how to use Swing Timers, etc. I've even used Timers myself, and SwingWorkers too (in one case to delegate icon loading to the background to prevent blockers on GUI instantiation).
Is there even a preferred method here? I haven't come across many / any standalone game solutions in Java that don't rely on libgdx.

Use Swing Timer when:
You don't want to throttle or control the time between updates. Swing Timer only guarantees "at least" duration (it will trigger AFTER a given delay) and the length of time in which the event is processed may effect the amount of time before the next update.
So, if you have a delay of 16ms (rough 60fps), your callback takes 20ms to process, the time between the first and second callback may actually be 36ms
You would also use a Swing Timer when you want to use the existing (passive) rendering system supplied by Swing
Swing Timer is relatively simple and easy to use, it triggers callbacks within the Event Dispatching Thread, making it easy to modify the state of the game and schedule an updates to the UI, this reduces possible thread race conditions (between the painting and the updating)
Use Thread#sleep when:
You want more control over the timing, producing variable delays. In order to do this, you will need to manage your own Thread
This approach is more suitable to more complex animations and when you are using a BufferStrategy to control the output.
The reason for this is, with a Thread approach, you run the risk of race conditions between your thread changing the state and the paint cycle painting it. Instead, you will need to take control of the paint process yourself, so you know that when you paint something, the state does not change while you do it.
Using this approach provides more flexibility and control to make decisions about when things get done (and how), but increases the complexity and your responsibility for doing things

Thread.sleep is almost certainly used in the implementation of javax.swing.Timer and java.util.Timer, but these days the only real use case of Thread.sleep is for creating a timeout on something, typically an I/O connection. I used this once at work way back for delaying updating the GUI after requesting the users messages until a certain amount of time past from the last message sent from the server. I also used it here
In your case, you should be using the swing timer for your game loop

Related

Regarding good practices with scheduling in Java

I'm building a game from the ground up in Java, using only standard libraries. So far I've got a game that prints ASCII characters in a swing window to represent 3d objects. It's pretty cool. Anyway, since I don't know about threading or scheduling, I'm wondering if I'm using some bad practices that could cause issues later on. I have one repeating task running to update the level every tenth of a second, but whenever I want to delay something, I use
Executors.newScheduledThreadPool(1).schedule... etc etc.
Is it good to make a "new scheduled thread pool" every time I want a new delayed task to run once, or should I try to keep one instance going? If it's good to reuse instances, when is it appropriate to make a new one?
Concurrency in Swing applications is tricky: everything that impacts the GUI needs to be executed on a single thread (called the event-dispatch thread). So when you set up a separate thread to perform some long-running background task (e.g. generating a map for an area the player isn't viewing yet) then you need to work carefully to synchronise with anything that might impact the GUI.
In general you have two options for the simpler use cases:
If it's a short activity that immediately impacts the GUI then use a Timer to trigger an event on the event-dispatch thread. See here.
If it's a long activity then use a SwingWorker. See here.
There are plenty of other ways to achieve interaction with other threads (e.g. see SwingUtilities.invokeLater and SwingUtilities.invokeAndWait) but given you have said you are just starting out I would suggest sticking to one of those two for now. They take care of most of the complexity for you and let you focus on your game logic.

Java: Using Swing for programming games

I am relatively new to game development. I have been developing games and studying game development for 2-3 months now. I use Java.
I have always used Swing for my graphics (aka, the entire game is displayed on a JPanel, using a Graphics2D object). I had no trouble with this up until now.
Very recently, I came across a problem in my most recent project. Some method has problems with being called in consistent time intervals (sometimes it runs every 15-16 milliseconds, as it should, and sometimes it starts to run every 3000 (!) milliseconds).
I did some frustrating debugging and some research, and found out that the reason this happens is probably because I'm not handling Swing and threads right.
My entrie game loop runs inside the run() method of a thread (which is not the EDT). So I'm modifying Swing elements outside of the EDT all of the time. Obviously this was bound to cause problems.
When I found out this was the problem was, I thought:
"Hey, I'll simply use SwingUtilities.invokeLater() in order to run the gameloop inside the EDT!"
But then I remembered, that just as it's 'forbidden' to manipulate Swing elements outside of the EDT, it's also problematic to manipulate non-Swing objects from inside the EDT (I think... is this correct?).
If so, then I have no idea how to develop games in Java using Swing without running into weird problems.
My question is:
How can I develop games safely, using Swing? What would be good guidelines for me to be strict about in order to avoid problems involving Swing and threading? Any instructions every game developer who uses Swing should know?
This is very important for me to understand, since I really want to progress with game development using Java, but if I won't understand this, I'm always going to run into weird problems and won't be able to progress.
Thank you for your help
As long as you don't modify anything but the graphics drawn on the panel, you should be ok most of the time. Just like a single non-EDT thread works most of the time. As long as you don't add or remove any gui elements, don't resize anything, don't hide anything etc., Swing won't fiddle with its internal details enough to cause race conditions between your thread and the EDT - most of the time.
Even the case that the user minimizes the panel while your non-EDT-code is drawing on it will not cause crashes - the panel will probably throw away its old graphics context and start working with a new one, but the old context will remain valid until you release it (this is different from C++ where a delete invalidates the object immediately, which causes crashes when a different thread still uses a local pointer).
The problem is that if you're using the "i've yet to see a case where it goes wrong, always worked for me" approach, you're relying on undefined behaviour, and your code may start crashing as soon as you update your JVM.
The best thing you can do is set up your GUI on the EDT thread, run your game logic on a different thread, have a timer call repaint() on the panel every 20 ms (or whatever you want your frame rate to be). Then, have a class object that holds everything needed to display the current game state. Within a synchronized code block, let the panel's paint() generate its own copy of the object , and have paint() use the copy while the main thread calulates whatever the game needs. The main thread should use the same synchronized to write to the class object of course. That way, you get the maximum possible separation between the threads.
Just running your whole game thread on the EDT probably won't do, as anything your game does that might take a while will cause the UI to freeze. And anything that will need a lot of UI resources will affect your game logic.
BTW, are you sure your initial problem (long delays every now and then, but not always) isn't a result of garbage collection? I've seen this several times; if you aren't using the parallel garbage collector, GC might run for several 10's of a second and block everything else.

Alternative to SwingWorker or how to implement it in this case...?

I have hundreds of different functions that run in the EDT. A great deal of them include long-running tasks and some include changes to the GUI. Occasionally the GUI hangs for users but it is hard to keep track of all the locations this happens due to the GUI hangs not happening in the same areas 100% of the time. The issue is not high priority because the hang usually starts working after a minimize/maximize of the window, but it needs to be done eventually.
After some research I discovered I could use doInBackground() under SwingWorker for any methods with labor-intesive work and use done() for GUI drawing. Also I believe I can use SwingUtilities.invokeLater for every GUI drawing that happens to be in the doInBackground() function. However, I want to avoid adjusting every one of the hundreds of functions in my code.
Is there a way I can use a single SwingWorker and send any long-running methods to the doInBackground() function? Using the invokeLater function multiple times for every misplaced GUI code where a SwingWorker would be used is not a problem as it is not that frequent.
If this is not possible is there some kind of alternative I can use? Thank you.
All methods that update the GUI must be invoked on the EDT, otherwise you may end up with some unexplained GUI behavior (which sounds like what you are seeing). You could have repaints that don't happen properly, thread races, etc.
It is not advised to run long running tasks on the GUI because they will cause the GUI to become unresponsive, so for long running tasks, SwingWorker is a good solution to use (note that the process and done methods are called on the EDT automatically so your worker can do its long running work in doInBackground but you can safely update the GUI without using SwingUtilities.invokeLater from the done method).
As you mentioned you have hundreds of methods and you don't want to call SwingUtilities.invokeLater every time, you might want to look into one of the task frameworks. The Swing Application Framework was developer under JSR-296 http://java.sun.com/developer/technicalArticles/javase/swingappfr/ but is not actively supported, but still provides a nice framework.
http://en.wikipedia.org/wiki/Swing_Application_Framework is a list of alternative frameworks.
It sounds like you are going to need to do some significant rewriting in your application. Calling GUI methods from outside the EDT is unsafe to do.
I don't see how what your asking would be possible. Swing has no way of knowing of what would qualify as a "long running" method call before execution. If the method is already being executed (on the EDT) Swing can't simply pick it up and move it to a new thread. Even if you would indicate which method calls should be run in background threads pulling it off would be hard. The only way I can think of to make this possible in Java is with AOP (you could intercept the method calls). But implementing AOP would be harder then reimplementing your existing application to use SwingWorkers.
It sounds like the architecture of your Swing application is broken. Long running tasks must not be executed on the EDT. I'm sorry but I think you just have to bite the bullet on this one. If you want your application to feel snappy, responsive and have predictable behavior you will have to fix this by putting the long running code in background threads.
If your application uses a lot of background tasks you might want to use the excellent Swing Task API. Otherwise you will find yourself in a SwingWorker spaghetti quite fast.
for every GUI drawing that happens to be in the doInBackground()
You can't call Swing drawing, updating, etc. methods in the 'doInBackground()' method (well actually you can, but you must not do that). This is because this is the method which gets executed off the EDT. GUI drawing and component updates must only be called in the 'done()' method of a SwingWorker.

Issues with Swing timers

I have 3 timers running on my application which takes care of different action. Timer 1 will deals with automatic logout of the application, timer 2 deals with updating a table, timer 3 deals with updating the color of swing buttons. First timer uses the calculation based on the variables and its values, second and third timers works out of MYSQL queries.
Now when i run this application on an average performance machine the application is not moving .I need to wait for few seconds to a normal click to happen or a window to open. Is it something to do with the timers ? If yes do I have any alternative suggestions to get rid of this timer problem?
It could well be the timers, if they are performing considerable work when fired. It's not usually a good idea to use swing timers for long-running tasks, since they will block the EDT and freeze the UI.
Here are some suggestions to avoid this:
Use a java.util.Timer rather than the swing timer. This will run the database code on a background thread, avoiding blocking the event queue.
Continue to use the swing timer, but have the timer action simply start a SwingWorker to perform the task. This gives the benefit of background processing with the ability to post updates to your UI, if it's a operation that takes more than a second or so to execute.
The problem isn't how many timers you have, but how long each timer takes to do it's work, since the timer's actionPerformed method is run on the swing event thread, meaning that while a timer is doing it's thing, no UI updates can happen.
That should not be related to the Swing timers, that is something else in your code. You need to debug the application to see what is causing the delay.
From what I remember, swing timers fire events on the same thread used for rendering, so you dont tend to get exceptions due to incorrect thread interractions - I have used them in the past for animations without issue - I suspect the answer lies elsewhere in your code. Have you tried profiling the code at the point where you are having an issue?
Is it OK if I run 5 timers at the same time?
All instances of javax.swing.Timer "perform their waiting using a single, shared thread." The limit occurs when the tread becomes saturated. As a practical matter, each Timer may have multiple listeners, but "the handlers must execute quickly to keep the GUI responsive."

What happens when Swing's threading policy is violated?

In the past few years I've mostly done UI development in Eclipse, which is very conservative in terms of thread access: any attempt to change a property on a UI widget (e.g., color, text) from outside the UI thread throws an exception.
I am now looking at an existing program in Swing that has a window with a large number of custom widget. There is a separate threads that runs a mutation function for each of these widgets, and the mutation function reads the value of some things (e.g., label colors and values) and writes some (e.g., changes background colors). Note that there is no custom painting involved or anything like that, just a bunch of changes to the sub widgets it contains which are mostly JLabels.
At present, this runs from the separate thread, not from the Swing event thread. This thread goes over all the 400 widgets and calls the mutator on each. The updates seem to work correctly, but the GUI is unresponsive to user input.
If I take the whole thing, which runs for about 0.4 msec from outside the Swing thread and wrap every call to a mutator in an invokeLater or invokeAndWait, the UI is a lot more responsive.
What I'm trying to understand is:
1) Is it sometimes legitimate to make all these calls from outside the Swing thread?
2) What is the impact on the Swing thread and why is the UI less responsive when I call it from outside?
From "Nothing" to intermittent problems to "Everything Broke, pull everyone off to work on the GUI!"
The main (most obvious) visual effect is that if you hold up the GUI thread (like someone presses a button and you do a sleep(5000) or something), your GUI won't repaint. It can't because you are holding onto the only thread it's allowed to pass you! This makes people think Java is really slow. It's not bad, but it's easy enough to program that a lot of people who don't bother researching practices like this have produced shipping products.
The next biggest problem is that when you are drawing the screen in another thread (like the one passed to main), it can have strange behavior. Swing is already too picky about how you render your frames--take out threading as a variable!
Finally, rarely (or often if you are calling a swing component in a tight loop on the wrong thread) you can get thread collisions. If that happens an exception may be thrown (or not) and something will probably render wrong, but it may not be obvious.
1) Is it sometimes legitimate to make all these calls from outside the Swing thread?
There are a few exceptions (setting the text value of a text field, for example, does automatic EDT proxying for you) - but there are no situations where it is better to do so. If you are performing lots of updates, you can do them all in a single EDT call (a single call to invokeLater()) instead of individual calls - but even that sort of batching very rarely helps things. Long and short: Perform operations on Swing components from the EDT. That includes reads and writes.
2) What is the impact on the Swing thread and why is the UI less responsive when I call it from outside?
Well, the EDT is responsible for updating the GUI. If you call from outside, it isn't 'less responsive' - it's that the actual low level system calls that update the user interface don't occur (at all). What is probably happening in your app is that the original developers are getting lucky and changing state in the swing component without creating a really nasty race condition. Then some other event is causing a repaint to occur on the EDT, which results in the component being updated. This may appear to be a 'lack of responsiveness' - but what's really happening is a 'lack of screen refresh'.
The EDT is just a regular thread, but it is a bit special in that it runs in a tight loop that processes GUI related signals (draw commands, for example). The semantecs of posting these types of commands on the EDT is really, really different from what we typically think of as Java threading (it involves submitting operations to a message pump).
Long and short - all those Javadocs that say 'only interact with Swing objects on the EDT' are written for a reason. Don't mess with it. If you want to do background processing, fine - but you are responsible for proxying the interaction with the J* components back onto the EDT (most generally using invokeLater() ).
There really are no exceptions. Kevin is partially correct - the JTextComponent.setText() is advertised as thread safe. However, looking at the 1.6 code, it provides synchronization on the document object and does not use the EDT. This is fine, unless another swing component (or something that controls swing components) is listening to the document object. Save yourself the trouble of worrying about it, and just always use the EDT - like Kevin says, there really are no situations (that I'm aware of) to do otherwise.
Hard to say without digging into the code; the behavior is undefined. If your background tasks were long running (> a few seconds), you'd see the opposite effect - using the EDT will make the UI unresponsive while your tasks are running.
Fortunately, it sounds like doing it the right way is working best for you anyway. :)
Sun used to say it was ok to use other threads with components that haven't been realized, but later recanted:
Related stackoverflow question
Check out Sun's UI tutorial on swing and concurrency (I'd post the link, but this is my first answer on stackoverflow0.
The basic problem is that non-thread-safe objects are executed in a multithreaded fashion. Even something as simple as reading a HashMap can be caught in an infinite loop. Because AWT uses locks (badly), you can also end up with deadlocks. However, you are likely to get away with it, although you might find that an updated version of Java suddenly causes you issues on some customer machines.
(BTW: It's AWT's Event Dispatch Thread, not Swing's.)
For (1) as a rule of thumb anything that updates pixels on screen must be called from the Event Dispatching Thread (EDT). Where some JVMs may handle updates from outside the EDT acceptably you should never rely on this working, some machines and different look and feels will not work acceptably. The behaviour is undefined - and this could explain the lack of responsiveness you have seen.

Categories