Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ignoring the event dispatch thread allow this program to work?

As I tried to see if I could answer this question earlier today. I realized that I don't fully understand the Event Dispatch Thread (EDT). Googling both confirmed and helped with that and clarified why I don't. (This might also be relevant to understanding.)

The code sets up a GUI and later (as in the earlier question) updates a text field until a flag is unset.

I have several questions/requests.

  • Please explain why the code below runs fine if both calls (to swingInit and doIt) are outside the invokeLater block (as shown), since both calls affect or query the GUI yet neither are executing on the EDT (are they?). Isn't that inviting failure?

  • Code also runs if call to swingInit is inside and doIt outside invokeLater. So swingInit is executed on the EDT, but shouldn't doIt not executing on the EDT be a problem? (I was surprised that this worked. Should I have been?)

  • I guess I understand why it hangs if doIt is inside invokeLater regardless of where swingInit is: the purpose of invokeLater is ONLY to initialize the GUI (right?).

  • Should doIt only be initiated (possibly from an event occurring) on the EDT but certainly not inside invokeLater block?

(The history of the EDT concept is interesting. It was not always thus. See link above to "why I don't" understand it.)

import static java.awt.EventQueue.invokeLater;
import java.awt.event.*;
import javax.swing.*;

public class Whatever 
{
  static boolean flag = true;
  static JTextField tf = new JTextField("Hi",20);
  static JPanel p = new JPanel();
  static JFrame f = new JFrame();
  static JButton b = new JButton("End");

  public static void main(String[] args)
  {
    swingInit();

    invokeLater
    (
      new Runnable()
      {
        @Override
        public void run() 
        {
    //    swingInit();
    //    doIt();
        }
      }
    ); 
   doIt();      
  } 

  static void swingInit()
  {
     b.addMouseListener
    (
        new MouseAdapter()
        {
          @Override
          public void mouseClicked(MouseEvent e)
          {
            flag = false;
            JOptionPane.showMessageDialog(null,"Clicked... exiting");
            System.exit(0);
          }
        }
    );

    p.add(tf);
    p.add(b);
    f.add(p);
    f.setVisible(true);
    f.pack();
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
  }

  static String getInfo(){
    return "Hello... " + Math.random();
  }

  static void doIt(){
    while(flag)     
      tf.setText(getInfo());
  }; 
}
like image 775
DSlomer64 Avatar asked May 08 '15 19:05

DSlomer64


People also ask

What is event dispatch thread in Java?

The event dispatching thread (EDT) is a background thread used in Java to process events from the Abstract Window Toolkit (AWT) graphical user interface event queue.

What is SwingUtilities invokeLater () used for?

An invokeLater() method is a static method of the SwingUtilities class and it can be used to perform a task asynchronously in the AWT Event dispatcher thread. The SwingUtilities. invokeLater() method works like SwingUtilities. invokeAndWait() except that it puts the request on the event queue and returns immediately.

What is SwingUtilities invokeLater new runnable ()?

SwingUtilities class has two useful function to help with GUI rendering task: 1) invokeLater(Runnable):Causes doRun. run() to be executed asynchronously on the AWT event dispatching thread(EDT). This will happen after all pending AWT events have been processed, as is described above.

How do you update Swing component from a thread other than EDT?

You can use invokeAndWait() and invokeLater() to update a Swing component from any arbitrary thread.


1 Answers

Taking each of your bullet points:

  • The code is launched on the Main thread - the EDT is run in parallel. swingInit returns after constructing the UI which is then under control of the EDT, allowing dotIt to do its thing in parallel on the main thread

  • Similar situation as above, but here you are guaranteeing construction of the UI on the EDT (as recommended by Oracle).

  • A long running task is placed onto the EDT, preventing it from showing (if placed before swingIt) or painting and interaction (if placed after). the purpose of invokeLater is ONLY to initialize the GUI The purpose is to place non-thread safe Swing calls onto the EDT. If within the main method, I would recommend using SwingUtilities.invokeAndWait

  • If you wish to update the UI like this, consider doing so with a SwingTimer.

Running EDT specific, non-thread safe code outside the EDT doesn't guarantee failure, but it does invite failure (via conflicts when two (or more) threads attempt to update data at the same time).

I once spent hours tracking down a mysterious NullPointerException, only to realize it was a LookAndFeel issue whose calls were not on the EDT. Lesson learned.

like image 85
copeg Avatar answered Sep 27 '22 19:09

copeg