public static void main(String[] args)
3. При нажатии кнопки " Start Counting", actionPerformed о запускается внутриEDT. И EDT теперь полностью захвачен вычислительным циклом. Другими словами, пока происходят вычисления в цикле, EDT занят, и не может обрабатывать другие события (т. е., нажатие кнопки " Stop Counting" или закрытие окна), а также обновновление формы невозможно до окончания цикла счета, только тогда EDT освобждается. В результате вся форма и ее элементы " заморожены" до окончания цикла.
Ркеомендуется запускать GUI В EDT черезВЫЗОВ invokeLater (), потому что множество GUI компонент не являются гарантированнро потокобезопасными (thread-safe). Распределение доступа к GUI компонентам в едином потоке гарантирует потокобезопасность. Предположим, что мы запустили конструктор напрямую в main () (используя поток " main" ): public static void main(String[] args) { new UnresponsiveUi(); }
Последовательность действий будет следующей: 1. Метод main () стартует в потоке " main". 2. Новый поток " AWT-Windows" (Daemon thread) запускается командой-конструктором " new UnresponsiveUi ()" (из-за" extends JFrame" ). 3. После выполнения " setVisibie (true)" создаются два других потока - " AWT-Shutdown" и " AWT-EventQueue-0" (i. e., the EDT). 4. Поток " main" " живет" и после того, как метод main () завершается. Запукается новый поток с именем " DestroyJavaVM". 5. Запущены 4 потока - " AWT-Windows", " AWT-Shutdown", " AWT- EventQueue-0 (EDT)" и " DestroyJavaVM". 6. Нажатием кнопки " Start Counting" запускается actionPerformed() внутри EDT. В предыдущем случае планировщик EDT запускается сразу методом invokeLater(), тогда как в последнем примере EDT стартует после setVisibie(). Пример 5. 2. 2. Изменим обработчик кнопки " Start Counting", запустив вычисления в отдельном потоке:
JButton btnStart = new JButton(" Start Counting" ); cp. add(btnStart); btnStart. addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { stop = false; // Create a new Thread to do the counting Thread t = new Thread() { @Override public void run() { // override the run() for the running behaviors*/ for (int i = 0; i < 100000; ++i) { if (stop) break; tfCount. setText(count + " " ); ++count; // Suspend this thread via sleep() and yield control to other threads. Also provide the necessary delay. try { sleep(10); // milliseconds } catch (InterruptedException ex) {} } } }; t. start(); // call back run() } });
Создается новый поток с помощью анонимного вложенного класса. Переопределяем run() метод, который выполняет наши вычисления. Метод start() запускает run() на выполнение в своем собственном потоке. Способность к реагированию, таким образом, несколько улучшается. Но необходимое значение подсчета все еще не отображается как следует, и все еще существует задержка в ответ на нажатие кнопки " STOP". Это происходит потому, что поток подсчета не уступает добровольно управления потоку-планировщику EDT - " замороженный" EDT не может обновлять форму и реагировать на события. Однако, JVM может заставить поток подсчета уступить управление согласно алгоритму-планировщику, что в результате выливается в задержку обновления формы. Пример 5. 2. 3. Изменим программу, добавив вызов метода sleep() обработчику кнопки " Start Counting": sleep() дает возможность циклу подсчета уступить (yield) управление потоку планировщику (event-dispatching thread) для обновления формы и отклик на кнопку " STOP". Программа подсчета теперь будет работать так, как нужно, sleep () обеспечит необходимую задержку. btnStart. addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent evt) { stop = false; // Create a new Thread to do the counting Thread t = new Thread() { @Override public void run() { // override the run() for the running behaviors*/ for (int i = 0; i < 100000; ++i) { if (stop) break; tfCount. setText(count + " " ); ++count; // Приостановка потока методом sleep() передача управления другим //потокам. Обеспечение необходимой задержки в миллисекундах. try { sleep(10); // milliseconds } catch (InterruptedException ex) {} } } }; t. start(); // call back run() } });
Метод sleep() приостанавливает текущий поток и устанавливает его в состояние ожидания на указанное количество миллисекунд. Теперь может быть запущен другой поток (sleep() может быть прерван путем запуска метода interrupt() этого потока, что вызывает InterruptedException() В этом случае, поток, созданный ля вычислений уступает (yields) управление добровольно другим потоком после каждого счета (путем установки " sleep(10)" ). Это позволяет потоку-планировщику обновлять окно при каждом нажатии на кнопку " STOP".
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|