Объяснение потока обработки событий Java
Недавно я начал изучать и изучать основы программирования GUI на Java.
Программируя некоторое время, я выполнял только бэкэнд-работу или работу, и в результате ближе всего к пользовательским интерфейсам я получил командную консоль (смущенно, я знаю).
Я использую Swing и, насколько я могу понять, это означает, что я также использую AWT.
Мой вопрос основан на этом фрагменте кода:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new frame.setVisible(true);
}
} );
Я изучал это некоторое время, так как хотел полностью понять этот странный фрагмент кода и несколько раз встречал термин "поток обработки событий". Поправь меня, если я не прав, но насколько я понимаю; это связано с использованием нескольких потоков и с тем, как Java Swing интерпретирует эти потоки. Я также понял, что приведенный выше код используется, чтобы убедиться, что все потоки "безопасны", прежде чем он создаст окно, следовательно, invokeLater?
Я прочитал это:
"Вы можете вызывать только те методы, которые работают с кадром, из потока диспетчеризации событий"
и что только при определенных обстоятельствах вы можете вызывать методы, которые работают с кадром, из основного метода.
Может кто-нибудь объяснить мне, что именно представляет собой ветка диспетчеризации событий?
Как это относится к нескольким потокам выполнения и как эти потоки небезопасно вызывать из основного метода? Также зачем нам этот invokeLater?
Можем ли мы не просто создать окно, как любой другой объект?
В своем исследовании я натолкнулся на препятствие, так как не понимаю эти отношения и идеи.
Еще одно замечание: я хотел бы основывать свои знания на глубоком понимании, так как считаю, что это приводит к наилучшему общему результату и, как результат, к лучшим программам. Если я глубоко понимаю, как что-то работает, то вы можете эффективно использовать советы и настройки, а не просто повторять их в коде, поэтому, пожалуйста, не бойтесь давать мне дополнительные подробные объяснения и расширять мои знания.
Спасибо.
2 ответа
Поток EventDispatching - это специальный поток, которым управляет AWT. По сути это поток, который выполняется в событии обработки бесконечного цикла. Метод java.awt.EventQueue.invokeLater - это особый способ предоставления некоторого кода, который будет выполняться в очереди событий. Написание среды пользовательского интерфейса, которая безопасна в среде с многопоточностью, очень сложно, поэтому авторы AWT решили, что они будут разрешать операции над объектами GUI только в одном специальном потоке. Все обработчики событий будут выполняться в этом потоке, и весь код, который изменяет графический интерфейс, должен также работать в этом потоке.
Теперь AWT обычно не проверяет, что вы не запускаете команды gui из другого потока (среда WPF для C# делает это). так что можно написать много кода и быть в значительной степени агностиком к этому и не сталкиваться с какими-либо проблемами. Но это может привести к неопределенному поведению, поэтому лучше всего всегда следить за тем, чтобы код GUI выполнялся в потоке диспетчера событий. invokeLater предоставляет механизм для этого.
Итак, классический пример - вам нужно запустить длительную операцию, такую как загрузка файла. Таким образом, вы запускаете поток для выполнения этого действия, а затем, когда оно будет завершено, вы будете использовать invokeLater для обновления пользовательского интерфейса. Если вы не использовали invokeLater и вместо этого просто обновили пользовательский интерфейс напрямую, у вас может возникнуть состояние гонки и может возникнуть неопределенное поведение.
В Википедии есть больше информации: http://en.wikipedia.org/wiki/Event_dispatching_thread
Также, если вам интересно, почему авторы awt не просто делают многопоточный инструментарий, вот хорошая статья: https://community.oracle.com/blogs/kgh/2004/10/19/multithreaded-toolkits-failed-dream
EventDispatchThread
(EDT) - это специальная тема, зарезервированная только для графического интерфейса Swing и связанных с * событий Swing, например, создание / изменение / обновление Swing JComponents, больше для задаваемых вопросов здесь и здесь
весь вывод в графический интерфейс от BackGround Tasks
, Runnable#Thread
должен быть включен в invokeLater() из синхронизированных объектов в invokeAndWait();