Поток выполнения при использовании Swing
Я только начинаю разбираться с GUI-программированием на java. Вот тривиальная программа (из "Head First Java" О'Рейли), которая на первый взгляд кажется простой для понимания, но есть аспект, который я не понимаю.
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame frame=new JFrame();
JButton button = new JButton("click me");
frame.getContentPane().add(button);
frame.setSize(300,300);
frame.setVisible(true);
}
}
Эта простая программа, будучи скомпилирована и запущена, откроет окно с кнопкой на нем.
Чего я не понимаю, так это того, что происходит с потоком исполнения. Когда я запускаю эту программу, статический основной метод классаTest
выполняется, все команды в main()
выполняются - так почему же процесс не завершается после появления окна? Почему я все еще сижу на том, что выглядит как бесконечная петля? Что такое зацикливание?
Если я добавлю строку
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Затем я нахожу результат еще более imcomprehensible. Теперь, конечно, программа завершается. как только я закрою окно. Но опять-таки я не понимаю, почему. Фрейм будет находиться в стеке, но я не вижу, где находится поток программы, и просто существование чего-то в стеке отсутствует. достаточно, чтобы сохранить программу живой, не так ли? Мне не хватает чего-то фундаментального, что, насколько я могу судить, не описано в книге, которую я читаю. Я немного удивлен этим - "Head first Java" до сих пор была очень хороша в указании тонкостей и объяснении того, что на самом деле происходит, но, похоже, не затрагивает этот момент (по крайней мере, я не заметил).
2 ответа:
Почему процесс не завершается после появления окна?
Потому что виртуальная машина Java завершает работу только после завершения всех потоков, не являющихся демонами. Хотя это и не очевидно, на самом деле в вашей программе есть два потока: основной поток и поток диспетчеризации событий , который делает все, что связано с компонентами Swing GUI. Поток диспетчеризации событий продолжается до тех пор, пока видны все компоненты графического интерфейса.
Собственно программа, хотя и может работа, это неправильно, потому что вы создаете и получаете доступ к компонентам Swing из основного потока. Вы должны выполнять всю работу GUI в потоке диспетчеризации событий. То есть это должно быть что-то вроде:
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { JFrame frame=new JFrame(); JButton button = new JButton("click me"); frame.getContentPane().add(button); frame.setSize(300,300); frame.setVisible(true); }); }
Процесс Java завершается, когда умирает последний не-демонический поток. Обычно существует только один, поток
main
. При отображении компонентов Swing запускаются дополнительные недемоновские потоки для диспетчеризации событий и вывода графического интерфейса. Они завершаются, когда последний компонент верхнего уровня удаляется. В вашем примере потокmain
умирает после выхода из методаmain
. Вы можете посмотреть на потоки с помощью отладчика илиjvisualvm
из инструментов JDK.Остальная часть потока графического интерфейса является событием управляемый. Когда вы, например, нажимаете на кнопку закрытия кадра, событие генерируется и отправляется соответствующим слушателям в потоке диспетчеризации событий.
Установка
JFrame.EXIT_ON_CLOSE
в качестве операции закрытия по умолчанию похожа на добавление прослушивателя событий по умолчанию к кадру. Довольно жесткий, он просто отключает JVM без уважения к остальной части состояния приложения.