What does SwingUtilities.invokeLater do?
As other answers have said, it executes your Runnable
on the AWT event-dispatching thread. But why would you want to do that? Because the Swing data structures aren't thread-safe, so to provide programmers with an easily-achievable way of preventing concurrent access to them, the Swing designers laid down the rule that all code that accesses them must run on the same thread. That happens automatically for event-handling and display maintenance code, but if you've initiated a long-running action - on a new thread, of course - how can you signal its progress or completion? You have to modify a Swing control, and you have to do it from the event-dispatching thread. Hence invokeLater
.
SwingUtilities.invokeLater
Do I have to use each time I need to update the GUI components?
No, not if you're already on the event dispatch thread (EDT) which is always the case when responding to user initiated events such as clicks and selections. (The actionPerformed
methods etc, are always called by the EDT.)
If you're not on the EDT however and want to do GUI updates (if you want to update the GUI from some timer thread, or from some network thread etc), you'll have to schedule the update to be performed by the EDT. That's what this method is for.
Swing is basically thread unsafe. I.e., all interaction with that API needs to be performed on a single thread (the EDT). If you need to do GUI updates from another thread (timer thread, networking thread, ...) you need to use methods such as the one you mentioned (SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, ...).
What is SwingUtilities.invokeLater
Nothing bad will happen if you're updating it from the EDT while following guidelines.
That is...
If invokeLater is called from the event dispatching thread -- for
example, from a JButton's ActionListener -- the doRun.run() will still
be deferred until all pending events have been processed.
Source
If that isn't the case, invokeLater()
is required.
It schedules a Runnable
which will be executed on the EDT (event dispatching thread).
what is SwingUtilities.invokeLater(new Runnable())
You are creating an instance of an anonymous implementation of the Runnable
interface and passing it to invokeLater
, which will put it on a queue. Another thread, the Event Dispatch Thread, pops Runnables off that queue and invokes their run
method. (Note that this is indeed a simplistic explanation and does not correspond 100% with reality.)
In terms of the effect you as the programmer are interested in, this makes the following line of code:
chatWindow.append(text);
to be executed not on the current thread, but on the Event Dispatch Thread (EDT). If you tried to execute it on your current thread, it would result in undefined behavior because Swing is not thread-safe and all GUI operations must happen on the mentioned EDT.
SwingUtilities.invokeLater takes a Runnable and runs it on the EDT?
What is new Runnable() {}?
new Runnable() {
public void run() {
createAndShowGUI();
}
};
This declares an anonymous class and instantiates a new instance of it. It is basically equivalent to this:
class Creator implements Runnable {
public void run() {
createAndShowGUI();
}
}
new Creator();
Before Java 8 lambdas, an anonymous class is a way to do a kind of functional programming. Passing a Runnable to invokeLater
is like passing a function that the EDT can execute later whenever it wants (by calling run
on it).
What does invokeLater do with the Runnable?
Initially, all it does is create an event to wrap it (an InvocationEvent) and put it at the end of a queue.
After queuing the event, invokeLater
notifies the EDT (which wakes up if it was waiting). The EDT's own run method is an infinite loop that processes events. It looks something like this (very paraphrased):
public void run() {
while(true) {
EventQueue eq = getEventQueue();
synchronized(eq) {
while(eq.hasNextEvent()) {
processOneEvent(eq.getNextEvent());
}
try {
eq.wait();
} catch(InterruptedException ie) {}
}
}
}
When the EDT gets to the new InvocationEvent, it calls run
on the Runnable, which calls createAndShowGUI
.
So passing a Runnable to invokeLater
or invokeAndWait
lets you run any code you want on the EDT.
How soon is run called?
In most cases, immediately or almost immediately. The EDT is very responsive. The 'Later' part of 'invokeLater' is just a hint to us that:
run
is executed asynchronously. The thread that callsinvokeLater
may continue past the call before the event is processed.- Other events may be processed first.
Of course invokeAndWait
exists as an alternative if a synchronous call to run
is desired. (Though it should be noted that invokeAndWait
may also cause other events to be processed if they were queued before the new InvocationEvent.)
Asynchronous
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("hello");
}
});
System.out.println("world");
This may print
hello
world
and it may print
world
hello
because the calling thread may or may not continue before (or even while) the event is processed. It depends on the system's thread scheduler.
Synchronous
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("hello");
}
});
System.out.println("world");
This will definitely print
hello
world
because the calling thread will wait for run
to complete before it continues (unless an exception is thrown).
invokeAndWait
uses a wait and notify scheme to achieve this. A monitor object is created and given to the InvocationEvent. invokeAndWait
calls wait
after posting the event and the InvocationEvent calls notifyAll
after run
completes on the EDT. The wait and notify scheme is a reason invokeAndWait
cannot be called on the EDT. The EDT does not have a way to stop in the middle of one event to process a different one.
What happens if more than one event is queued?
The EDT processes events one at a time, in the order they are queued and according to their priority. Some events can also get merged (a regular InvocationEvent will not). Most events are normal priority. A PaintEvent (like from calling repaint
) is typically low priority and certain system events are of higher priorities.
In the specific example you've given:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
SwingUtilities.invokeLater(new Runnable() {
public void run() {
doSomethingElse();
}
});
Since they are the same kind of event and the same priority, the doSomethingElse
event will be processed after the createAndShowGUI
event is done.
Similarly, if something like this were done:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("world");
}
});
System.out.println("hello");
}
});
That will print
hello
world
because the world
Runnable gets run after the hello
Runnable completes.
SwingUtilities.invokeLater() why is it needed?
Swing objects are not thread safe. SwingUtilities.invokeLater()
allows a task to be executed at some later point in time, as the name suggests; but more importantly, the task will be executed on the AWT event dispatch thread. When using invokeLater
, the task is executed asynchronously; there's also invokeAndWait
, which won't return until the task has finished executing.
Some information about the decision not to make Swing thread-safe can be found here: Multithreaded toolkits: A failed dream? [Archived]
Why to use SwingUtilities.invokeLater in main method?
The docs explain why. From Initial Threads
Why does not the initial thread simply create the GUI itself? Because almost all code that creates or interacts with Swing components must run on the event dispatch thread.
and 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.
Animations and SwingUtilities.invokeLater
Here is that self-contained code (good call on posting that, BTW) updated to use a Timer
as suggested by @MadProgrammer. In order to access the x
variable, it was moved into the action listener defined for the timer. In order to access the Timer
from within the action listener, it was moved to being a class attribute. The latter meant it was easier to move the bulk of the code into a constructor for an instance of the object.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Test {
Timer timer;
Test() {
int width = 854;
int height = 480;
String title = "Test";
BufferedImage bufferedImage = new BufferedImage(
width, height, BufferedImage.TYPE_INT_RGB);
JFrame frame = new JFrame();
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D graphics2D = (Graphics2D) graphics;
// when you have an ImageObserver, may as well use it
//graphics2D.drawImage(bufferedImage, 0, 0, null);
graphics2D.drawImage(bufferedImage, 0, 0, this);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width,height);
}
};
frame.add(panel);
frame.pack();
frame.setTitle(title);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
int size = height / 3;
ActionListener animationListener = new ActionListener() {
int x = -size;
@Override
public void actionPerformed(ActionEvent e) {
if (x <= width) {
Graphics2D graphics2D = (Graphics2D) bufferedImage.getGraphics();
graphics2D.setColor(Color.RED);
graphics2D.fill(new Rectangle2D.Double(x, 0, size, size));
graphics2D.setColor(Color.GREEN);
graphics2D.fill(new Rectangle2D.Double(x, size, size, size));
graphics2D.setColor(Color.BLUE);
graphics2D.fill(new Rectangle2D.Double(x, 2 * size, size, size));
graphics2D.dispose();
panel.repaint();
++x;
} else {
timer.stop();
frame.dispose();
}
}
};
timer = new Timer(10, animationListener);
timer.start();
}
public static void main(String[] args) {
Runnable r = () -> {
new Test();
};
SwingUtilities.invokeLater(r);
}
}
Difference between SwingUtilities.invokeLater and SwingWorker Void, Object ?
SwingUtilities.invokeLater
takes a Runnable and invokoes it in the ui thread later. Usually for short running ui related work.
SwingWorker
runs the main work in a non ui thread - the worker thread. After the long running work is done the done()
method is invoked in the ui thread (Event Dispatch Thread).
But the SwingWorker's doInBackground()
method can also publish intermediate results by invoking the publish()
method. The SwingWorker
will than ensure that the results to publish are processed by the Event Dispatch Thread. You can hook in by implementing the process()
method.
Related Topics
What's the Difference Between Fx:Id and Id: in Javafx
Reading a List from Properties File and Load with Spring Annotation @Value
Most Simple Code to Populate Jtable from Resultset
How to Check If the User Is Pressing a Key
Struts2 Input Result: How Does It Work? How Are Conversion/Validation Errors Handled
Replace Implicit Wait with Explicit Wait (Selenium Webdriver & Java)
Why Does the Tostring Method in Java Not Seem to Work for an Array
How to Kill a Thread? Without Using Stop();
Using Switch Statement with a Range of Value in Each Case
Page Scroll Up or Down in Selenium Webdriver (Selenium 2) Using Java
Using Prepared Statements to Set Table Name
What Is the "Continue" Keyword and How Does It Work in Java
How to Call the Default Deserializer from a Custom Deserializer in Jackson
Java and Gui - Where Do Actionlisteners Belong According to MVC Pattern
Nosuchelementexception with Java.Util.Scanner
Why Does a Java Method Reference with Return Type Match the Consumer Interface
What Is the Correct Way to Structure This Kind of Data in Firestore