Java Basics

main and the GUI Event Dispatch Thread

Threads in a GUI system

There are at least three threads that are typically used in a GUI application.

  1. Initial thread - This is the thread that start main. Stops when main returns.
  2. Event Dispatch Thread (EDT) - Initializes and runs the GUI, and calls listeners.
  3. Worker threads - These should be started for any slow listener.

1. Initial thread

This is the thread that the main program starts on. The main program may do various intializations (eg, intializing the model), but the the last thing that is typically done in main on this thread is to start the EDT, Event Dispatch Thread. The initial thread is terminated when main finishes, and the only thread that continues at this point is the EDT.

2. Event Dispatch Thread (EDT)

Initialization on the EDT. The GUI should be initialized on the EDT, although for simple programs this is generally not necessary, and often not done. Early versions of Java didn't require it, but later versions of Java require GUI initialization on the EDT to avoid certain problems.

My examples generally don't initialize on the EDT, and I've got a nice long list of excuses: this is a consequence of history (some are old), laziness, and attempts to keep the very simple programs very simple. But because it might cause a problem, the examples will be changed.

setVisible(true) side-effect. Even if you didn't initialize the GUI on the EDT, a side-effect of calling setVisible(true) is to start the EDT thread, which continues to run and monitor the GUI.

Problem: Listeners called on EDT. The source of serious problems revolves around listeners. Listeners are called on the EDT, but while the listener is busy, the GUI is frozen because the thread which runs the GUI, the EDT, is busy. The solution is to run long-running listener actions on a worker thread.

3. Worker threads for long actions

When a listener is called (eg, actionPerformed), it's called on the Event Dispatch Thread, the same thread that runs the GUI. While the listener is being executed, the GUI is frozen! If the action is short (eg, less than 50 milliseconds), you can simply do it and return from the listener, and the user will never know that the GUI was not active for a fraction of a second. If you're doing something longer, eg, processing a lot of data or interacting over a network, you should start a "worker" thread to do the work.

Coordination concerns. Coordinating threads is not trivial; it's easy to get into race or deadlock situations, and communicating between threads can be an issue.

For example, the worker thread will often produce a result which should be displayed in the GUI, but the GUI should only updated from the EDT. The worker thread may periodically give an indication of it's progress, but showing a progress bar should be done on the EDT.

The Java 6 solution for listeners is to use SwingWorker. There have been earlier, incompatible, versions of SwingWorker, as well as other packages, such as Foxtrot, which to ease the pain of working with multiple threads. JSR 296 will propose other solutions.

In any case, examples in this tutorial will have to wait.

Example: GUI construction on EDT

For small programs there are no problems, but for building more complex GUIs, the initialization may require use of the EDT. To call the GUI constructor on the EDT, use code like the following.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
// File   : gui-tutorial/tw2/TinyWindow2T.java
// Purpose: Based on TinyWindow2, this shows how to initialize
//          the construction of a GUI on the EDT thread.
//          This is the recommended way, but for simple programs
//          is typically omitted.
// Author : Fred Swartz, 2007-01-15, Placed in public domain.

import javax.swing.*;

////////////////////////////////////////////////////// class TinyWindow2
class TinyWindow2T extends JFrame {

    //====================================================== method main
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {  //Note 1
            public void run() {
                TinyWindow2T window = new TinyWindow2T();
                window.setVisible(true);
            }
        });
    }
    
    //====================================================== constructor
    public TinyWindow2T() {   
        //... Set window characteristics
        setTitle("Tiny Window using JFrame Subclass");  
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    }
}

Notes

  1. This will call the run() method from the EDT.