Объяснение потока диспетчеризации событий Java

недавно я начал изучать и изучать основы программирования GUI на Java.

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

Я использую Swing и, насколько я могу собрать, это означает, что я также использую AWT.

мой вопрос основан на этом фрагменте кода:

java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
        new frame.setVisible(true);
    }
} );

Я исследуя это некоторое время, поскольку я хотел полностью понять этот странный фрагмент кода и несколько раз сталкивался с термином "поток диспетчеризации событий". Исправьте меня, если я ошибаюсь, но как я понимаю; это связано с использованием нескольких потоков и как Java Swing интерпретирует эти потоки. Я также понимаю, что приведенный выше код используется, чтобы убедиться, что все потоки "безопасны", прежде чем он создаст окно, следовательно, invokeLater?

Я прочитал это:

"вы можете вызывать только методы, которые работают на фрейме из потока диспетчеризации событий"

и только при определенных обстоятельствах вы можете вызывать методы, которые работают на фрейме из метода main.

может кто-нибудь уточнить мне, что именно такое поток отправки событий?

как это относится к нескольким потокам выполнения и как эти потоки небезопасны для вызова из основного метода? Также зачем нам этот invokeLater?

можем ли мы не просто создать окно как любой другой объект?

Я попал немного в дорожный блок в своих исследованиях, поскольку я не понимаю этих отношений и идей.

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

спасибо.

2 ответов


поток EventDispatching-это специальный поток, управляемый AWT. В основном это поток, который работает в бесконечном цикле обработки событий. Ява.ОУ.EventQueue.метод invokeLater-это специальный способ предоставить код, который будет выполняться в очереди событий. Написать UI framework, который безопасен в многопоточном окружении, очень сложно, поэтому авторы AWT решили, что они разрешат операции с объектами GUI происходить только в одном специальном потоке. Все мероприятие обработчики будут выполняться в этом потоке, и весь код, который изменяет gui, также должен работать в этом потоке.

теперь AWT обычно не проверяет, что вы не выдаете команды gui из другого потока (платформа WPF для C# делает это). таким образом, можно написать много кода и быть в значительной степени агностиком к этому и не столкнуться с какими-либо проблемами. Но это может привести к неопределенному поведению, поэтому лучше всего всегда гарантировать, что код gui работает на диспетчере событий нитка. invokeLater предоставляет механизм для этого.

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

Wikipedia имеет более подробную информацию: http://en.wikipedia.org/wiki/Event_dispatching_thread

также, если вам интересно, почему авторы awt не просто делают инструментарий многопоточным, вот хорошая статья: https://community.oracle.com/blogs/kgh/2004/10/19/multithreaded-toolkits-failed-dream


EventDispatchThread (EDT) - специальный поток, зарезервированный только для GUI Swing и связанных с ним событий *Swing, например, create/change/update Качели JComponents, больше для задаваемых вопросов здесь и здесь

все выходные данные в GUI от BackGround Tasks, Runnable#Thread должно быть заключено в invokeLater(), из синхронизированных объектов в invokeAndWait();