SwingUtilities.invokeLater() зачем он нужен?

Почему необходимо установить код обновления графического интерфейса пользователя в SwingUtilities.invokeLater()?

Почему бы не поработать с самим собой? Почему вызывающий абонент должен заботиться о том, как swing обрабатывает обновления пользовательского интерфейса?

Ответ 1

Объекты Swing не являются потокобезопасными. SwingUtilities.invokeLater() позволяет выполнить задачу в некоторый более поздний момент времени, как следует из названия; но что еще более важно, задача будет выполнена в потоке отправки событий AWT. При использовании invokeLater задача выполняется асинхронно; там также invokeAndWait, который не вернется, пока задача не завершит выполнение.

Некоторая информация о решении не создавать потокобезопасную Swing можно найти здесь: Многопоточные инструментарий: неудачный сон?

Ответ 2

Потому что обновления графического интерфейса должны выполняться в потоке отправки событий. Если вы работаете в другом потоке, выполнение обновления в invokeLater удаляет его из потока и в поток событий.

Больше объяснений здесь: http://www.oracle.com/technetwork/java/painting-140037.html

Умная вещь, связанная с большими обновлениями (например, перекомпоновкой JTable из базы данных) в Swing, заключается в том, чтобы получить базовую модель, обновить модель в своем потоке, а затем отключить уведомление с помощью invokeLater. Это держит ваш gui в ответ на события и перерисовку. Если обновление будет очень обширным, вы можете даже отключить эти уведомления с помощью invokeLater через регулярные промежутки времени, пока вы обновляете, например, каждую секунду или две.

Ответ 3

Качание однопоточное. Каждое обновление для пользовательского интерфейса должно происходить из так называемого EDT - потока потока событий, который является основным потоком графического интерфейса Swing (и, как мне кажется, AWT). Если вы этого не сделаете, тогда могут произойти странные вещи (хотя мне больше нравится Windows FOrms, который просто генерирует исключение, если вы делаете это неправильно).

При этом вам не нужно обертывать каждую операцию UI в SwingUtilities.invokeLater() - если код, который вы пишете, уже выполняется EDT, это не требуется. Поэтому ActionListener для нажатия кнопки не требуется. Но слушатель на внешнем объекте, работающий в каком-то другом потоке, который где-то обновляет JLabel - там вам это нужно.

Ответ 4

Swing не был написан для потокобезопасного инструментария GUI, поэтому все обновления GUI должны происходить из одного потока, чтобы избежать каких-либо взаимоблокировок. В Swing это поток диспетчера событий (EDT).

Подробнее см. Concurrent in Swing из учебника Java. Он также ссылается на эту запись в блоге о том, почему сложно написать многопоточный инструментарий GUI.

Ответ 5

Вся окраска компонентов должна выполняться в одном потоке, поэтому они отображаются правильно. Таким образом, компонент будет знать, какая часть уже была окрашена, а какая - нет.

Если вы вызываете метод, связанный с рисунком (краска, обновление, paintComponent, show, setVisible, pack и т.д.) вне EDT, вы будете пытаться рисовать в двух разных потоках, и это может вызвать проблемы.

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

Вам не нужно использовать его, если вы уже кодируете метод, который работает в EDT (например, actionPerformed или paint или один из них). Или если вы выполняете код, а не интерфейс (например, обработка файлов в фоновом режиме и т.д.)

Чтобы лучше понять все эти понятия, прочитайте: Правило единственного потока

Ответ 6

SwingUtilities.invokeLater()

Вызывает doRun.run(), который должен выполняться асинхронно в потоке диспетчеризации событий AWT. Это произойдет после того, как все ожидающие события AWT будут обработаны. Этот метод следует использовать, когда поток приложения должен обновлять GUI.
...

Ответ 7

Повторение других: Swing не является потокобезопасным, поэтому один поток должен выполнять все обновления, чтобы избежать проблем с w390. invokeLater - это метод утилиты для выполнения чего-то внутри потока обработки событий.

Почему Swing не делает это внутри: это мое впечатление... Я думаю, потому что это было бы излишним - проверить все места, где происходит обновление. Это раздуло бы код Swing, что бы повлияло на обзор и поддержку кода.

С другой стороны, это не так уж сложно для приложения узнать, не выполняет ли он внутри потока GUI и вызывает invokeLater. Это произойдет, когда собственное приложение запустило некоторый поток раньше.