Главная Тема против UI Thread в Java

Во многих фрагментах Swing, приведенных здесь в качестве ответов, есть вызов SwingUtilities#invokeLater из метода main:

public class MyOneClassUiApp {

    private constructUi() {
        // Some Ui related Code
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MyOneClassUiApp().constructUi();
            }
        });
    }
}

Но согласно статье Threads and Swing, безопасно создавать пользовательский интерфейс из основного потока:

Несколько методов являются потокобезопасными: в документации Swing API, поточно-безопасные методы отмечены этим текстом:

Этот метод является потокобезопасным, хотя большинство методов Swing не являются.

Графический интерфейс приложения часто может быть сконструирован и показан в основном thread: следующий типичный код является безопасным, если никакие компоненты (Swing или иначе):

public class MyApplication {
public static void main(String[] args) {
   JFrame f = new JFrame("Labels");
   // Add components to 
   // the frame here... 
   f.pack(); 
   f.show(); 
   // Don't do any more GUI work here... 
   } 
}

Итак, существует ли реальная (потоковая безопасность) причина для создания пользовательского интерфейса в основном через SwingUtilities#invokeLater, или это просто привычка, помнить об этом в других случаях?

Ответ 1

"Правило однопоточного Swing: компоненты и модели Swing должны быть созданы, изменены и запрошены только из потока диспетчеризации событий". - Java Concurrency на практике, также обсуждался здесь и здесь. Если вы не следуете этому правилу, вы не можете надежно построить, изменить или запросить какой-либо компонент или модель, которые предположили бы, что вы выполнили это правило. Возможно, программа работает корректно, только для того, чтобы таинственно провалиться в другой среде.

Ответ 2

Безопасно создавать свой Swing UI в основном методе, потому что как другие компоненты будут отображаться до того, как вы настроите свой пользовательский интерфейс? Пока вы не набросились на экран, все будет хорошо. Другими словами, это было бы плохо:

public class MyApplication
{ 
  public static void main(String[] args)
  { 
    JFrame f = new JFrame("Labels"); 
    // Add components to  
    // the frame here...  
    f.pack();  
    f.show();  

    // now make another frame:
    JFrame f2 = new JFrame("Labels2"); 
    // Add components to the 2nd frame here...  
    f2.pack();  
    f2.show();  
  }  
}

Если вы сделали это, у вас будет JFrame f, и вы будете добавлять компоненты Swing UI из потока отправки событий (EDT). invokeLater запускает код на EDT - это не помешает использовать его, если вы хотите дополнительного спокойствия.

Ответ 3

Я думаю, что использование SwingUtiltities.invokeLater() - это просто более простой способ выполнить некоторый код асинхронно. Иногда это требуется для определенного приложения: например, вы можете одновременно создавать два отдельных окна. Больше ничего.