JOptionPane.showMessageDialog поток безопасно?

Предполагается, что JOptionPane.showMessageDialog будет полезной утилитой для получения отзывов пользователей, поскольку она блокирует ваш текущий поток, пока вы ждете.

Поэтому я ожидал бы, что это будет поточно-ориентированным и что вам не нужно будет оборачивать вызов в invokeLater или invokeAndWait.

Это тот случай?

3 ответа

Решение

Взято из описания пакета javax.swing:

Политика потоков Swing

В общем, Swing не является потокобезопасным. Все компоненты Swing и связанные с ними классы, если не указано иное, должны быть доступны в потоке диспетчеризации событий. Типичные приложения Swing выполняют обработку в ответ на событие, сгенерированное жестом пользователя. Например, нажатие на JButton уведомляет все ActionListeners, добавленные в JButton. Поскольку все события, сгенерированные из жеста пользователя, отправляются в потоке диспетчеризации событий, это ограничение не влияет на большинство разработчиков.

Однако влияние заключается в создании и демонстрации приложения Swing. Вызовы основного метода приложения или методов в Applet не вызываются в потоке диспетчеризации событий. В связи с этим необходимо позаботиться о передаче управления потоку диспетчеризации событий при создании и отображении приложения или апплета. Предпочтительным способом передачи управления и начала работы с Swing является использование invokeLater. Метод invokeLater планирует Runnable для обработки в потоке диспетчеризации событий.

JOptionPane не документирует, что это потокобезопасный, поэтому вы должны использовать invokeLater(),

Вы должны вызывать этот метод только из потока диспетчеризации событий, так как это единственный поток, который должен взаимодействовать с компонентами Swing.

Если вы хотите приостановить фоновую обработку в ожидании обратной связи с пользователем, я предлагаю вам использовать реализацию SwingWorker, в которой doInBackground() метод периодически вызывает publish(), позволяя process() быть вызванным на нить Swing. doInBackground() может потенциально заблокировать, пока не будет предпринято какое-либо действие process(), Например:

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();

Нет, это не так. Поведение блокировки очень точно закодировано в очереди событий (путем добавления новой очереди, чтобы можно было обработать дальнейшие события, и блокировки этой). Как и для всех компонентов колебания, они могут использоваться только в очереди событий.

Другие вопросы по тегам