Is javax.swing.SwingUtilities.invokeLater nesessary? - java

So I have seen countless different GUI tutorials, and all of them have said to use this code:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
And although I may not quite understand what this exactly does, since I'm somewhat new to GUI, I do understand the basics of what it does... or so I thought. But then I, as an experiment, cut it all out, and just left:
public static void main(String[] args) {
createAndShowGUI();
}
And it appeared to work. So now I have a question: what is the purpose of keeping the first piece of code I had, rather than just using the second, when it seemed like the second worked just as fine? If it is necessary, what will happen if I don't use it?

In short, yes, it is necessary whenever you make changes to any Swing object (unless the API says they are thread safe).
Any changes you make to the GUI must be made on the Event Dispatch Thread (EDT) because the Swing objects are not thread safe. From the Event Dispatch Thread Tutorial
Swing event handling code runs on a special thread known as the event
dispatch thread. Most code that invokes Swing methods also runs on
this thread. This is necessary because most Swing object methods are
not "thread safe": invoking them from multiple threads risks thread
interference or memory consistency errors. Some Swing component
methods are labelled "thread safe" in the API specification; these can
be safely invoked from any thread. All other Swing component methods
must be invoked from the event dispatch thread. Programs that ignore
this rule may function correctly most of the time, but are subject to
unpredictable errors that are difficult to reproduce.
Calling SwingUtilities.invokeLater ensures that the code int he runnable is invoked on the EDT and you don't get weird errors. That is why when you removed that code it looks like everything is working, because in the situations you tested it probably did. But it might not always and you don't want to have code that works sometimes or has timing issues.

Related

Do JFrame windows in Swing run on their own separate threads?

I have three questions which are closely related in that they are born out of each other and represent a train of thought, so I am posting them under one question. It would not help me construct the big picture of my question if I posted them separately.
1) Could you please explain in simple language what SwingUtilities.invokeLater does? I understand threading, dare I say quite a bit, but still the language of the documentation confuses me. It says:
Causes doRun.run() to be executed asynchronously on the
AWT event dispatching thread. This will happen after all
pending AWT events have been processed. This method should
be used when an application thread needs to update the GUI.
In the following example the invokeLater call queues
the Runnable object doHelloWorld
on the event dispatching thread and
then prints a message.
If I put some effort in to make sense of what that says, I think here is what it says, but I couldn't be so sure about it. I think it says:
The invokeLater method schedules the main window creation and the setting up of its dispatcher / message pump on the primary thread of the application only and not on a separate thread. It does it by posting the message to create the window and set it up on the main / primary application thread. In other words, the main thread is saying to us, "The window you are asking me to create will be created after I am done doing everything else that is on my plate right now."
But then two things confuses me, which I list as the two questions below.
2) Then why do I need to implement the new window's message loop as a Runnable. This implies that I want a separate thread to execute that message loop.
3) I printed out the current thread Id's in the function that creates the window and the function that is the window's message loop, and they are both different threads. So, each window in Swing runs on its own thread? That is insane. Can you please explain to me what is happening here? And also if you could please explain in a paragraph or two the threading model of GUI applications created in Swing?
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainWindowEventLoop());
System.out.println(String.format("Main thread %1$d started.",
Thread.currentThread().getId()));
}
public class MainWindowEventLoop implements Runnable {
#Override
public void run() {
JFrame mainWindow = new MainWindow("Main Window");
System.out.println(String.format("Main window loop running on thread %1$d.",
Thread.currentThread().getId()));
}
}
Output:
Main thread 1 started.
Main window loop running on thread 14.
It's a little complicated, but Swing is not thread safe. To run the GUI asynchronously and safely, Sun/Oracle uses a locking pattern called Ad-Hoc Thread Confinement. All Swing components must run on the AWT EDT (Event Dispatch Thread) or the result is not thread safe.
Here's a link to Oracle's tutorial. Try to read all of those sections, see if it makes more sense.
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/
Each window does NOT run on its own separate thread. There is only one EDT. Each windows runs on the SAME thread, the EDT. Each Runnable you send to the EDT is executed sequentially, one after the other, when the EDT has the opportunity to do so. Hence the "later" part of invokeLater().
Basically all the swing windows are bounded to main thread. Every single component in swing runs as thread. After the completion of an event control again returns back to main thread which waits for an event to occur.

Why is it important to use invokeLater?

I recently found an example code:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
The createAndShowGUI() method opens a user interface window. Then I tried to trim the code as the following:
public static void main(String[] args) {
createAndShowGUI();
}
Both versions work equally well. What is the difference?
99% of the time either code will work.
However, Swing was designed such that all updates to Swing components should be done on the Event Dispatch Thread (EDT). Read the Swing tutorial on Concurrency for more information.
The problem is the 1% of the time when it might not work. You don't want to waste time trying to debug random problems.
SwingUtilities.invokeLater ensures that the code executes on the Event Dispatch Thread (EDT). Swing is single-threaded, all component instantiation and display should happen on the EDT. Things might seem to work otherwise, but you'll possibly run into issues.
Swing has single threaded Event Loop based design and is not thread safe, with only thread safe part being a set of invokeXXX() methods used to transfer control to the Swing event loop.
Your "broken" code works just fine because nothing else is trying to touch the same part of Swing data structures from within the Event Loop at the same time.
The "main" thread started by the JVM is not the Event Dispatch Thread.
from The Event Dispatch Thread
Some Swing component methods are labelled "thread safe" in the API specification; these can be safely invoked from any thread. All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.

Does displaying Java GUI requires some special treatment?

I was looking at some example code of GUIs in Java, and I was wondering what the proper way to display a GUI. Suppose a createAndShowGUI() method is written for some GUI. I saw something like this:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
Would it be wrong simply to call createAndShowGUI() at the end of the main method without the javax.swing stuff? Or I guess my real question is about what is going on here. I'm familiar with threads but I am not sure why it's necessary to make a new thread (is that what's going on here?) to display the GUI.
All interactions with the UI (Swing or AWT) MUST be executed from within the context of the Event Dispatching Thread.
Swing (and AWT) components are not thread safe, changing any of them from any thread other the EDT can lead to corrupted updates, paint artifices, dead locks and possibly crash the VM. They are also notoriously difficult to debug.
You might like to have a read through
The Event Dispatch Thread
The Single Thread Rule in Swing
Will the real Swing Single Threading Rule please stand up?
I should also add, when the main method is executed, it is running in what ever thread the VM created for it. This is guaranteed not to be the EDT, as it will not have begin started until it is needed.
This is why good Swing programs always start with something like EventQueue.invokeLater. You could also use SwingUtilities.invokeLater, but it's generally the same thing.
Because everything related to a GUI should be done through the Event Dispatch Thread (EDT), that is how Java manages the whole drawing of interfaces. Basically the method delegates the execution of the run() method of the passed Runnable object to the correct thread.
Mind that Runnable is not a Thread, it's just an interface to provide a method that does something (hence the class is runnable). But there is no thread involved here, the fact that Thread extends from Runnable is just because a thread is also a Runnable object in the sense that can execute something.

GUI doesn't work when synchronized method is run

I have an app with a main object (containing Swing GUI) and a supporting thread which calls on the handle() method of the object.
I noticed that when the handle() method is synchronized, while the thread is using the handle() method, the GUI on the main object are unresponsive. Code:
public synchronized void handle()){
//method code
}
i remove the synchronized keyword from handle(), the GUI is responsive even when the thread is using the handle() method.
An interesting thing to note is that when I used another object as a lock, the GUI becomes responsive again when the thread is using the handle() method. Code:
public void handle(){
synchronized(anotherObj){
//method code
}
}
This suggests that Swing GUI uses methods that are synchronized. Am I right? Feel free to point me to any resources - couldn't quite find what I wanted.
Thanks.
What is your "handle" method and what does it do? I believe that Swing does not use synchronization for the most part and its documentation in fact states in its API that it is not thread-safe (e.g., have a look here). Instead it uses a single thread for user interactions and program painting, the EDT or Event Dispatch Thread, and all programs that interact with Swing must respect this single thread model by calling most all Swing calls on the EDT. I suspect this is where your problem lies.
For more on Swing threading and use of background threads, please have a look here: Concurrency in Swing
Edit 1
(From my comment) I have to ask also, why this method is synchronized? Since we queue all Swing calls onto the event queue, this probably isn't necessary and is possibly harmful. A Swing program freeze almost always is due to a concurrency issue so this discussion is relevant.
You might want to make a small compilable test program (an SSCCE) that demonstrates your problem (the GUI freeze) and post it here so we can test it for ourselves.

How to figure out when I should make a function call within GUI thread

How can I know, whether I should make a function call within GUI thread.
if (SwingUtilities.isEventDispatchThread()) {
// ...
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
For example
// Should I call this within GUI thread?
jTable.getModel().setValueAt(...
Or
// Should I call this within GUI thread?
jComboBox.showPopup();
As I know, making operation in incorrect thread, may yield problem which is not easy to be detected. Hence, quite difficult for me to verify whether I am doing the correct stuff.
Currently, what I am doing is, If I am not sure, I will just call them in GUI thread
Not sure whether this is the best way, or there is a reliable way to figure out?
If you really need some ultra-generic thing "invoke ASAP" functionality, a helper like this is useful:
void invokeAsSoonAsPossible(Runnable action) {
if (SwingUtilities.isEventDispatchThread())
action.run();
else SwingUtilities.invokeLater(action);
}
// Usage:
invokeAsSoonAsPossible(new Runnable(){
#Override
public void run() {
jTable.getModel().setValueAt(...
}
});
But my experience tells me that it's a far better strategy to structure and document your code so that it gets easier to keep track of what is running where. If you've got a public method in a class which should be run on the EDT, JavaDoc is a good friend:
/**
* Blah blah blah, describe the method's purpose.
* <p>
* <strong>Note:</strong> This method should always be
* invoked on the Swing event dispatch thread.
*/
public Pony calulateValue() {
// go ahead and touch the components any way you please
}
You can also add an assertion in EDT-only methods as a kind of executable documentation:
assert SwingUtilities.isEventDispatchThread();
In short: If you have a hard time keeping track of which thread you're in, your code is probably so crufty that you have a hard time keeping track of anything, and you should worry about refactoring your code, not which thread you're on.
Actually
if (SwingUtilities.isEventDispatchThread()) {
// just do it, you're already in EDT
} else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// ...
}
});
}
All the code that involves Swing or AWT components/classes should be run in the EDT, ie. using SwingUtilities.invokeLater(Runnable) helper.
You can configure your app using Substance Look&Feel for testing purposes. It throws an exception if UI related code is run outside of EDT.
Almost all Swing methods needs to be executed on the UI thread. There are a few exceptions (such as some setMethods). These exceptions are documented in the API docs (usually says something like "this method is thread safe"). The general rule however, is that all GUI updates should take place on the UI thread.
In most situations you should know which thread you're currently in. It's ofter quite easy to tell. All call-backs triggered by GUI events are executed on the UI thread, and the actions in the main thread and all other threads you've started are not on the UI thread.
If you however do call code from your own threads sometimes and from the UI thread other times, you could, as you've shown in your question, determine if you're on the UI thread by calling EventQueue.isDispatchThread().
I would put the code to be executed in a separate method, updateGuiComponent(...) and do
if (EventQueue.isDispatchThread())
updateGuiComponent(...);
else
SwingUtilities.invokeLater(new Runnable() { // or invokeAndWait
public void run() { updateGuiComponent(...); }
});

Categories

Resources