Java Quiz Player

SwingUtilities.invokeAndWait usage Example

May 14, 2015

1. Swing Threads

GUI (Graphical User Interface) applications are inherently asynchronous. A user may select a menu item or press a button at any time, and expects that the application will respond promptly. Java Swing and AWT address this issue by creating a separate thread for handling user initiated events and updating the graphical view presented to the user.

The event handling code runs on a special thread known as the event dispatch thread (EDT). Most code that invokes Swing methods also runs on this thread. Most tasks are invocations of event-handling methods, such as ActionListener.actionPerformed. Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive or freezes.

Other tasks can be scheduled by the application code, using the static methods javax.swing.SwingUtilities.invokeLater or invokeAndWait.

To determine whether the code is running on the event dispatch thread, use the static method SwingUtilities.isEventDispatchThread.

2. The Example

This post shows how to use GUI actions (asynchronous) and non-GUI (synchronous) process together to get the desired user experience using the EDT and the application threads. The example uses the invokeAndWait.

The example app is a Swing GUI dialog where a user starts a process and waits for it to complete. The GUI has a status message area and buttons to start or interrupt the process and close the app.

GUI image

The app is a XYZ Database Restore program. The app supposes that a backup copy of the database is stored in a directory. The user selects the directory and starts the restore process by clicking Restore Database button. Once the process in initiated all the buttons are disabled (except the interrupt) and the user waits a few seconds until the process completes. The process completes - a status is displayed and the buttons are enabled for the user to proceed further.

When the Restore Database button is clicked, the buttons are to be disabled and a process start status message is to be displayed (as seen in the above screenshot). The restore process should start after these GUI actions complete. These two sets of actions cannot be run from the EDT, but from an application thread.

The GUI actions are run in an EDT using the invokeAndWait, and the restore process runs within the application thread. Both these together run from an application thread started from the actionPerformed method of Restore Database button's action listener (of type java.awt.event.ActionListener). Note that the action listener's action performed method code runs in an EDT.

The following are the details:

The user proceeds further with next actions - like close the dialog as the database restore is completed or work with any errors as shown in the status display.

3. The Code

The following code snippet shows the Restore Database button's action listener's action performed method (there is a link to download the complete program code at the bottom of this post):

 1:  public void actionPerformed(ActionEvent e) {
 2:		
 3:      System.out.println("actionPerformed isEventDispatchThread: " +
 4:          SwingUtilities.isEventDispatchThread()); // this returns true
 5:
 6:      // This code is to run in a non event dispatch thread.
 7:      final Runnable runInitially = new Runnable() {
 8:			
 9:          public void run() {
10:
11:             // These GUI actions need to be completed before the doDbRestore()
12:             restoreButton.setEnabled(false);
13:             closeButton.setEnabled(false);
14:             browseButton.setEnabled(false);
15:             interruptButton.setEnabled(true);
16:             messageArea.append(RESTORE_START + NEWLINE);
17:             System.out.println("invokeAndWait isEventDispatchThread: " +
18:                 SwingUtilities.isEventDispatchThread()); // this returns true
19:          }
20:      };
21:
22:      Thread appThread = new Thread() {
23:			
24:          public void run() {
25:				
26:              System.out.println("appThread isEventDispatchThread: " +
27:                  SwingUtilities.isEventDispatchThread()); // this returns false
28:
29:              try {
30:                  SwingUtilities.invokeAndWait(runInitially);
31:              }
32:              catch (InterruptedException | InvocationTargetException ex) {					
33:                  ex.printStackTrace();
34:             }
35:			
36:             // NOTE: Runs in a separate thread where the current thread waits
37:             // until the restore process completes in different thread.
38:             // See doDbRestore() for details.		
39:             boolean restoreStatus = doDbRestore(); 
40:
41:             if (restoreStatus) {
42:                  messageArea.append(RESTORE_SUCCESS + NEWLINE);
43:             }
44:             else {
45:                  messageArea.append(RESTORE_FAILURE + NEWLINE);
46:             }
47:					
48:             browseButton.setEnabled(true);
49:             closeButton.setEnabled(true);
50:             interruptButton.setEnabled(false);
51:          }
52:      }; // Thread
53:			
54:      appThread.start();
55:  }

4. The Output

The following is the output on the console after the database restore is completed. Verify the type of thread at each stage of the process from the point of clicking the Restore Database button. Note the above code snippet's lines 3, 26, 17 print the following output:

actionPerformed isEventDispatchThread: true
appThread isEventDispatchThread: false
invokeAndWait isEventDispatchThread: true

Note the invokeAndWait method should be used only when an application thread needs to update the GUI. It shouldn't be called from the event dispatching thread.

5. Download

Download source code here: SwingInvokeAndWaitExample.zip

NOTE: Java SE 7 is required to compile and run the code.

6. Useful Links

Return to top