Does SwingUtilities.invokeLater accept Runnable and run it on EDT?

I am confused with the signature of SwingUtilities.invokeLater . A Runnable object is required. Is this Runnable passed to an Event Dispatch Thread? Why can't I directly call createAndShowGUI in the run EDT method (if possible)?

I have read articles on how EDT and invokeLater work, but they confuse me with the passed Runnable object.

 SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); 

And what happens if I call SwingUtilities.invokeLater again right under the call?

 SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); SwingUtilities.invokeLater(new Runnable() { public void run() { doSomethingOnTopOfGUI(); } }); 
+7
java multithreading swing awt event-dispatch-thread
source share
2 answers

What's New Runnable () {}?

 new Runnable() { public void run() { createAndShowGUI(); } }; 

This declares an anonymous class and instantiates a new instance. This is basically equivalent to this:

 class Creator implements Runnable { public void run() { createAndShowGUI(); } } new Creator(); 

Prior to Java 8 lambdas, an anonymous class is a way to make some kind of functional programming. Passing Runnable to invokeLater similar to passing a function that EDT can do later when it wants (by calling run on it).

What does invokeLater do with runnable?

Initially, all he does is create an event for his wrapper ( InvocationEvent ) and put it at the end of the queue.

After the sequence of events, invokeLater notifies EDT (which wakes up if it is waiting). The EDT native start method is an endless loop that processes events. It looks something like this (very rephrased):

 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 hits the new InvocationEvent, it calls run in Runnable, which calls createAndShowGUI .

So passing Runnable to invokeLater or invokeAndWait allows you to run whatever code you want on the EDT.

How soon is the call made?

In most cases, immediately or almost immediately. EDT is very responsive. The "later" part of "invokeLater" is just a hint that:

  • run runs asynchronously. The thread that invokeLater calls can continue the call before the event is processed.
  • Other events may be handled first.

Of course, invokeAndWait exists as an alternative if a synchronous call to run is required. (Although it should be noted that invokeAndWait may also result in other events being 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"); 

It can print

  hello
 world

and he can print

  world
 hello

because the calling thread may or may not continue until (or even while) the event is being processed. It depends on the system thread scheduler.

Synchronous

 SwingUtilities.invokeAndWait(new Runnable() { public void run() { System.out.println("hello"); } }); System.out.println("world"); 

It 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 notification scheme to achieve this. A monitor object is created and assigned to an InvocationEvent. invokeAndWait calls wait after the event is dispatched, and InvocationEvent notifyAll calls after run end in the EDT. The wait and notification scheme is the reason invokeAndWait cannot be called on the EDT. EDT cannot stop in the middle of one event to handle another.

What happens if more than one event is queued?

The EDT processes events one at a time, in order of priority and according to their priority. Some events can also be combined (a regular InvocationEvent will not). Most events are a normal priority. A PaintEvent (such as a repaint call) usually has low priority, and some system events have higher priorities.

In the specific example that you specified:

 SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); SwingUtilities.invokeLater(new Runnable() { public void run() { doSomethingElse(); } }); 

Since they are the same event and the same priority, the doSomethingElse event will be processed after the createAndShowGUI event createAndShowGUI .

Similarly, if something like this was done:

 SwingUtilities.invokeLater(new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { System.out.println("world"); } }); System.out.println("hello"); } }); 

It will print

  hello
 world

since world Runnable starts after hello Runnable completes.

+11
source share

You can use SwingUtilities.invokeLater() from any thread to queue a task that should be running on the EDT. This is useful in several situations, especially in multi-threaded applications, as a convenient way to update GUI elements from threads other than the GUI, and also when starting the application (which your example prompts) from main() , which runs in the main thread, and not in EDT.

eg:.

 // main is not executed in the EDT public static void main (String[] args) { // create and initialize GUI in the EDT to avoid potential thread-safety issues. SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } 

You might want to read the official event dispatch topics guide , which should explain some of your misconceptions about what EDT is and how you access it.

+6
source share

All Articles