9

JOptionPane.showMessageDialog is supposed to be a useful utility for getting user feedback as it blocks your current thread while you wait.

I would expect therefore that it would be thread-safe and that you wouldn't need to wrap the call in an invokeLater or an invokeAndWait.

Is this the case?

Tom Martin
  • 2,498
  • 3
  • 29
  • 37
  • There is a related discusion in the answers and comments of [this question](http://stackoverflow.com/q/4750128/741249). One argument is that even though it isn't thread safe, in practice this isn't a problem and there is no need to run it on the EDT. – THelper Sep 11 '14 at 12:12

3 Answers3

8

Taken from the javax.swing package description:

Swing's Threading Policy

In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread. Typical Swing applications do processing in response to an event generated from a user gesture. For example, clicking on a JButton notifies all ActionListeners added to the JButton. As all events generated from a user gesture are dispatched on the event dispatching thread, most developers are not impacted by the restriction.

Where the impact lies, however, is in constructing and showing a Swing application. Calls to an application's main method, or methods in Applet, are not invoked on the event dispatching thread. As such, care must be taken to transfer control to the event dispatching thread when constructing and showing an application or applet. The preferred way to transfer control and begin working with Swing is to use invokeLater. The invokeLater method schedules a Runnable to be processed on the event dispatching thread.

JOptionPane does not document that it is thread safe, so you have to use invokeLater().

tangens
  • 39,095
  • 19
  • 120
  • 139
  • JOptionPane is never used outside the event queue thread, If you attempt modifying or anything, then it'd be thread unsafe. – bestsss Jan 21 '11 at 00:52
7

You should only be calling this method from the event dispatch thread, as this is the only thread that should interact with Swing components.

If you wish to pause background processing whilst awaiting user feedback I suggest you use a SwingWorker implementation whereby the doInBackground() method periodically calls publish(), allowing process() to be called on the Swing thread. doInBackground() can then potentially block until some action is taken within process(). For example:

new SwingWorker<Void, Void>() {
  private volatile boolean done;

  // Called on background thread
  public void doInBackground() {
    for (int i=0; i<1000000; ++i) {
      // Do work

      if (i % 1000 == 0) {
        publish(); // Will cause process() to be called on Event Dispatch thread.

        synchronized(this) {
          wait();
        }

        if (done) {
          System.err.println("Background thread stopping.");
          return null;
        }
      }
    }
  }

  // Called on Event dispatch thread.
  protected void process(List<Void> chunks) {
    if (JOptionPane.showConfirmDialog(getFrame(),
      "Do you want to quit?", "Confirm Quit",
      JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {

      done = true;        
    }

    synchronized(this) {
      notifyAll();
    }
  }
}.execute();
Adamski
  • 54,009
  • 15
  • 113
  • 152
  • Thanks, I am familiar with SwingWorker. – Tom Martin Oct 20 '09 at 16:50
  • No problem ... although it's arguable whether you want to actually pause your background thread whilst displaying the dialog; it probably makes more sense for it to keep processing until the user makes a decision. – Adamski Oct 20 '09 at 17:21
5

No, this is not the case. The blocking behavior is very specifically coded into the event queue (by pushing a new queue so that further events can get processed and blocking this one). As with all swing components, they can only be used in the event queue.

Yishai
  • 90,445
  • 31
  • 189
  • 263