I've got a question about what would be the correct practice to use the invokeLater method of SwingUtilities.
So to begin, I'd like to confirm that I am understanding it correctly.
From what I understand, changes to the GUI must be done on the EDT, because Swing components aren't thread safe. The invokeLater method takes a Runnable as an argument, and anything contained in that runnable will be run on the EDT. Therefore any calls made to Swing components are put in a kind of queue, which are executed one at a time on the EDT.
With that out of the way, my question then is: what is good practice for using this? From what I can see there are at least two ways to do it:
1) In the main method, place all code, such as GUI creation, Controller creation, and even the Model creation (assuming a MVC type pattern), in a Runnable that is invoked by the invokeLater method. Of course, this is assuming that any long running tasks in the Model would be executed with a SwingWorker.
2) Place GUI creation in a invokeLater, but Controller creation and Model creation in the main method. Then whenever you need to access a Swing component from a Controller, you pop said code in an invokeLater method to place it on the EDT queue.
What one of these two would be considered best practice, or bad practice? And if neither of these two are good, what would be the better way to go about this?
Any info would be hugely appreciated.
Thanks.
That's indeed an interesting question and the accepted answer isn't fully responding it.
Both approaches you suggest are acceptable and will work fine, but I believe the first one is better than the second approach (do it all on the EDT, and if there is some long-running tasks do them on a SwingWorker, or a new thread if they're not related to Swing).
Why? As #ThomasKrägler pointed out here:
While you could split these tasks (model, controller and view creation) between main thread and EDT (and possibly gain a few milliseconds until the UI is first shown) it would also complicate the design of the application (multithreading is no easy topic) and litter the code base with invokeLater() calls.
Take into account that the EDT won't need to process anything until the model and controller are initialised (and thus starting the view too). So you can use the EDT to initialise them, as it won't have any negative impact on your UI (there is no UI yet).
Doing it this way, you'll save a lot of invokeLater calls and possible errors forgetting to call invokeLater. Your code will look much cleaner too.
SwingWorker isn't special, it's just some wrappers around common scenarios. It will call invokeLater on your behalf so really both cases you present are just instances of the same thing.
Just make sure you follow these two rules:
1. Don't stall the EDT
2. Perform Swing-related code on the EDT
Related
My background is mainly in JavaScript, where functions are first-class objects and I can pass them around easily as callbacks. That is very much the way of JavaScript.
Now I am attempting to build a simple Java app. The problem at hand is to (1) use Swing to let the user browse to a file to open, and then (2) do some stuff with it. Let's say I have a method like this
void doStuff(File file) {
//stuff
}
that needs to run on the file chosen by the user. In JavaScript, the doStuff function would simply be passed as a callback. How would one do this in Java?
I'm aware that it is possible to do callbacks in Java by, say, making a Callback interface with a void run() method. But is that idiomatic? How should this kind of thing be done? How would an experienced Java programmer choose to do it?
Also, when I use callbacks, it looks like nearly everything happens on the Event Dispatch Thread. I suppose I could, from the EDT, create a new third thread, but it seems like my doStuff function should be executing on the main thread. And I can't figure out any way to make that happen. Nor do I know if it's necessary or desirable to make it happen.
Put simply, "do stuff" will parse and import data from the file.
Since this involves file or resource input, then it should not be done on the EDT. The best solution IMO would be to
do the importing and parsing within the doInBackground() method of a SwingWorker
add a PropertyChangeListener to the SwingWorker
have this listener listen to the worker's state property, specifically for a new value of SwingWorker.StateValue.DONE
in this listener, you'll then be notified when the worker has completed its task. You'll want to be sure to call get() on the SwingWorker when its done, so you can get any end value that you want it to produce, and so you can capture and respond to any and all exceptions that might have occurred during its run.
For more on this, please check out the tutorial -- Lesson: Concurrency in Swing
Do you suggest using SwingWorker mainly so that this process doesn't take place on the EDT, thereby locking up the user interface?
Yes. Any thread would serve that purpose though, but the main advantage of using the SwingWorker is because while it will run the process in a background thread, it also has great mechanisms for providing end and interim results on the EDT, as well as built-in functionality to monitor progress.
I've recently started learning and exploring the basics of GUI programming in Java.
Having been programming for a while I have only done backend work or work and as a result the closest I've gotten to user interfaces is the command console (embarrassing I know).
I'm using Swing and as far as I can gather that means by extension I am also using AWT.
My question is based on this piece of code:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new frame.setVisible(true);
}
} );
I have been researching this for a while as I wanted to fully understand this strange piece of code and have come across the term 'Event-Dispatching Thread' multiple times. Correct me if I'm wrong but as I understand it; it has to do with using multiple threads and how Java Swing interprets those threads. I gather as well that the above code is used to make sure all the threads are 'safe' before it creates the window, hence the invokeLater?
I have read that:
"You can only call methods that operate on the frame from the Event-Dispatching Thread"
and that only under certain circumstances can you call methods that operate on the frame from the main method.
Can somebody please clarify to me what exactly the Event-Dispatching Thread is?
How it relates to multiple threads of execution and how those threads are not safe to be called from the main method? Also why do we need this invokeLater?
Can we not just create the window as any other object?
I've hit a bit of a road block in my research as I'm not grasping these relations and ideas.
A side note is that I like to base my knowledge on in-depth understanding as I believe this leads to the best overall outcome and as a result the best programs. If I understand in-depth how something works then you can use the tips and tweaks effectively rather than just parroting them back in to code, so please don't be afraid to give me some extra in-depth explanations and broaden my knowledge.
Thank you.
The event dispatch thread is a special thread that is managed by AWT. Basically, it is a thread that runs in an infinite loop, processing events.
The java.awt.EventQueue.invokeLater and javax.swing.SwingUtilities.invokeLater methods are a way to provide code that will run on the event queue. Writing a UI framework that is safe in a multithreading environment is very difficult so the AWT authors decided that they would only allow operations on GUI objects to occur on a single special thread. All event handlers will execute on this thread and all code that modifies the GUI should also operate on this thread.
Now AWT does not usually check that you are not issuing GUI commands from another thread (The WPF framework for C# does do this), meaning it's possible to write a lot of code and be pretty much agnostic to this and not run into any problems. But this can lead to undefined behavior, so the best thing to do, is to always ensure that GUI code runs on the event dispatch thread. invokeLater provides a mechanism to do this.
A classic example is that you need to run a long running operation like downloading a file. So you launch a thread to perform this action then, when it is completed, you use invokeLater to update the UI. If you didn't use invokeLater and instead you just updated the UI directly, you might have a race condition and undefined behavior could occur.
Wikipedia has more information
Also, if you are curious why the AWT authors don't just make the toolkit multithreaded, here is a good article.
EventDispatchThread (EDT) is special thread reserved only for Swing GUI and *Swing's related events e.g. create/change/update Swing JComponents, more for asked questions here and here
all output to the GUI from BackGround Tasks, Runnable#Thread must be wrapped into invokeLater(), from synchronized Objects into invokeAndWait();
When I start my GUI interfaces, what can happen if I don't use invokeLater?
Does that mean all rest of the GUI paints/updates/etc. will be in the main thread?
Will calling a repaint outside of an invokeLater make all subsequent calls fall into the main thread?
Basically this:
void main()
{
JFrame jmf();
setVisible(jmf);
}
------------- VS -------------
void main()
{
SwingUtilities.invokeLater(new Runnable(){
run(){
JFrame jmf();
setVisible(jmf);
}
}
});
NOTE: In cases with small GUI, I if I don't put the invokeLater it seems to work fine. And in fact the application doesn't terminate although the last line of the main is executed.
I have read quite a few articles on why we should use it pertaining to the fact that Swing is not thread safe (it is single threaded and so on), but I really didn't read the repercussions of not calling invokeLater (partially because of my limited knowledge in Threads)
The reality is, nothing might happen or the world will end. It's next to near impossible to predicate, this is the nature of multi-threaded environments...
Unless you are doing some really dynamic setups, until the a frame is made visible it "should" be okay not to do it within the context of the EDT.
The problem comes down to the fact that different platforms are implemented differently (at the native level). For example, the original requirement for using invokeLater when starting your UI seems to have come from deadlocks on the Sun OS many years back.
I've also seen some issues with Java 7 (but my predecessors idea of the thread was weird to say the least). The general advice is, use invokeLater to create and display your UI. Run all UI code within the context of the EDT
It will also reduce the risk of you having to spend weeks trying to replicate and track down those weird anomalies (by running you all you UI code from within the EDT)
Updated based on comments from the OP
repaint makes a request to the RepaintManager, that makes decisions about what and when something should be paint. It will actually post a "paint" event directly on to the Event Queue, which is then processed by the Event Dispatching Thread, so repaint is actually on (of the few) thread safe methods...
Take a look at
Painting in AWT and Swing
Initial Threads
Will the real Swing Single Threading Rule please stand up?
Why is Swing threading model considered wrong and how should it be?
The general advice would be, you should use invokeLater because that's how the API has been designed, doing anything else is inviting problems...
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.
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.