1

Upon reading this question, I decided to execute the code that displays a message dialog in my application on the Event Dispatch Thread (EDT).

To do this, I modified my method that shows a message dialog from:

private static void showMessage(final Component parent,
                                final String message,
                                final String title,
                                final int type) {
    System.out.println("Before dialog.");
    JOptionPane.showMessageDialog(parent, message, title, type);
    System.out.println("After dialog.");
}

to:

private static void showMessage(final Component parent,
                                final String message,
                                final String title,
                                final int type) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            System.out.println("Before dialog.");
            JOptionPane.showMessageDialog(parent, message, title, type);
            System.out.println("After dialog.");
        }
    });
}

However, I was surprised to find that the behavior changed significantly after this change. Before I modified the above method to run on the EDT, it would print "Before dialog", followed by displaying the dialog - blocking until it was closed - and then printing "After dialog". This is the expected behavior. Once the method was modified, I found that "Before dialog" is printed, the dialog briefly appears (basically flickers on and off), and then "After dialog" is printed.

It almost appears that the JOptionPane.showMessageDialog(...) call stops blocking when executed on the EDT. What gives?

I suspect it may have something to do with my application shutdown code. I display a message before the application begins to shut down to inform the user about the critical error. However, in my shutdown method, I ensure that it is also executed on the EDT:

public static synchronized void shutdown() {
    if (userShutdown) {
        return;
    }
    if (!SwingUtilities.isEventDispatchThread()) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                shutdown();
            }
        });
        return;
    }
    userShutdown = true;
    System.out.println("Shutting down...");
    // ...
}

If my understanding of the event queue is correct, because I call showMessage before shutdown, the shutdown call that is on the EDT should be executed after the message dialog closes (since it should block until the dialog closes), so the code in shutdown should not affect the behavior of showMessage.

Community
  • 1
  • 1
Martin Tuskevicius
  • 2,590
  • 4
  • 29
  • 46
  • 1
    It could be invokeLater, if it's not already running in the EDT, you could use invokeAndWait instead, which will block the current thread until the run method returns – MadProgrammer Apr 02 '16 at 07:45
  • It works now that I've replaced it with `invokeAndWait` but why? The documentation for `invokeLater` says that: "This will happen after all pending AWT events have been processed." – Martin Tuskevicius Apr 02 '16 at 07:48
  • It's all in the naming, invokeLater will, at some point in the future, invoke the Runnable in the EDT, but will allow the current thread to continue running, where as invokeAndWait will block the current thread until after the Runnable is executed and the run method returns – MadProgrammer Apr 02 '16 at 07:50
  • I guess the confusion is the fact that it's called a queue. The EDT is *one* thread, so I would expect the `Runnable` tasks submitted to be executed synchronously, regardless if submitted via `invokeLater` or `invokeAndWait`. – Martin Tuskevicius Apr 02 '16 at 07:54
  • 1
    Yep, but because of the JDialog works, it's still processing events off the event queue – MadProgrammer Apr 02 '16 at 08:01

0 Answers0