Когда использовать SwingUtilies.invokeAndWait/invokeLater

Я где-то читал, что для любого потока, который влияет на визуальные изображения gui, он должен запускаться в EDT с использованием SwingUtilities.invokeAndWait/invokeLater

Для базового gui необходимо ли положить что-то вроде new SwingGUI().setVisible(true); в строку EDT с помощью invokeAndWait? Просто для отображения?

Считается ли это?

Ответ 1

Короткий ответ на ваш вопрос: да, даже вызов setVisible должен произойти на EDT. Чтобы узнать, является ли текущий поток EDT, вы можете использовать метод EventQueue#isDispatchThread

Некоторые ссылочные ссылки:

Изменить: после прочтения ссылок, которые я предоставил, кажется, что некоторые из статей на сайте Oracle устарели, поскольку в документе по-прежнему можно создавать компоненты Swing в другом потоке. Существует вопрос fooobar.com/questions/50076/..., в котором содержатся некоторые хорошие ответы и ссылки на блог-посты и статьи о новой политике (новые, как в течение нескольких лет)

Ответ 2

Да, если вы касаетесь объекта Swing, вы должны сделать это на EDT. В большинстве случаев вы уже находитесь, но если нет, используйте классы SwingUtilities. Причина этого в том, что классы Swing не являются многопоточными, поэтому вы можете столкнуться с неприятными проблемами, если вы получите доступ к ним в других потоках. И может быть, что setVisible() делает много вещей под обложками, чтобы что-то показывать (например, перекладывать вещи). Лучше быть в безопасности.

Ответ 3

Все, что вызывается из

public static void main(String[] agrs) {

напрямую (без появления другого потока или использования invokeLater) работает в основном потоке.

Доступ к объектам графического интерфейса с основным потоком, пока они могут быть доступны (одновременно) с помощью EDT (который запускается при вводе пользователя), может вызвать проблемы с потоками. Вызов invokeLater заставляет задачи (runnables) запускаться на EDT, предотвращая одновременный доступ к другим задачам EDT, т.е. нажатия кнопок и т.д.

Если вы можете быть уверены, что EDT не занят (до того, как первое окно установленоVisible (true)), вы можете получить доступ к графическому интерфейсу из основного потока. Если вы можете быть уверены, что EDT не имеет ссылки на компонент, над которым вы работаете (это вне области EDT), то есть. прежде чем он добавится в любой контейнер, вы можете получить к нему доступ из основного потока без обращения к нему EDT одновременно, поскольку EDT не имеет возможности достичь этого.

Ответ 4

Все, что обращается к объектам Swing, должно делать это через Thread Dispatch Thread (EDT). Это одно небольшое исключение (о чем я расскажу позже). Цель EDT - обрабатывать любые события, которые могут произойти из-за IO (события мыши и клавиатуры). Довольно много времени это может означать изменение макета вашего графического интерфейса. Swing не был разработан, чтобы быть потокобезопасным, что означает, что если два потока попытаются одновременно изменить один и тот же компонент, вы можете получить поврежденный графический интерфейс. Поскольку уже существует один известный поток для доступа к компонентам Swing (EDT), ни один другой поток не должен пытаться модифицировать их или даже читать их состояние.

Теперь, в исключительный случай, когда вы можете манипулировать объектами Swing вне EDT. Прежде чем какие-либо компоненты станут видимыми, IO не может запускать события. Поэтому основной поток может настроить графический интерфейс Swing, а затем установить один JFrame для видимости. Так как теперь есть видимые события IO кадра, и основной поток не должен пытаться модифицировать компоненты Swing. Этот параметр следует использовать только для запуска графического интерфейса и, действительно, только с игрушечными проблемами.

Я говорю, что следующее прекрасно и не вызовет проблем, если вы просто играете с вещами.

public static void main(String[] args) {
    // create components
    JFrame f = new JFrame();
    ...

    // do layout and other bits of setup


    // show gui to user
    f.setVisible(true);
}