Объясните, что делает следующий код? - PullRequest
15 голосов
/ 05 февраля 2011
java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
        new NewJFrame().setVisible(true);
    }
});

Пожалуйста, скажите мне, что на самом деле делает приведенный выше код.Я ищу построчное объяснение.особенно в первой строке и скажите мне, почему мы используем это и в каких сценариях мы должны использовать это.

Ответы [ 5 ]

27 голосов
/ 05 февраля 2011

В этом примере вы видите произвольный класс, производный от Runnable.Этот анонимный класс переопределяет метод run интерфейса runnable.Затем этот анонимный класс создается и передается методу EventQueue.invokeLater, который является статическим методом.Этот метод добавляет объект в ... ну ... eventQueue.В EvenQueue есть много событий, таких как события клавиатуры или мыши или что-то еще.Существует поток, который постоянно опрашивает данные из этой очереди.Как только этот поток достигнет анонимного класса, который был создан здесь, он выполнит метод run (), который создаст экземпляр объекта класса NewJFrame и установит его как видимый.

Весь смысл сделать это так сложноявляется то, что новая часть JFrame (). setVisible (true) выполняется не в основном потоке, а в потоке диспетчеризации событий.В Swing вы должны выполнить весь код, который изменяет пользовательский интерфейс в потоке диспетчеризации событий.

4 голосов
/ 16 июня 2016

Single-Thread-Model и EDT

Большинство современных библиотек пользовательского интерфейса принимают single-thread-model.Это означает, что все манипуляции с компонентами пользовательского интерфейса ДОЛЖНЫ выполняться в одном и том же потоке.Зачем?Это потому, что разрешение обновления компонентов пользовательского интерфейса из нескольких потоков приведет к хаосу, так как большинство методов объекта Swing не являются "потоко-безопасными" .Для простоты, эффективности и надежности принята модель с одним потоком.

В Swing тот самый поток, который обслуживает single-thread-model, называется Поток диспетчеризации событий , т.е. EDT.Он не предоставляется Swing.Он предоставляется Abstract Window Toolkit , т. Е. AWT.

Рабочий поток против потока пользовательского интерфейса

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

java.awt.EventQueue

Обмен данными происходит через модель очереди сообщений.java.awt.EventQueue - это тот самый класс, который предоставляет очередь событий глобально .Эта глобальная очередь событий служит каналом связи с EDT.EDT получает сообщения из этого EventQueue и соответственно обновляет компоненты пользовательского интерфейса.Если какая-то другая часть вашей программы хочет манипулировать пользовательским интерфейсом, эта часть кода должна вызвать EventQueue.invokeLater() или EventQueue.invokeAndWait(), чтобы поместить сообщение в EventQueue.EDT обработает все ожидающие сообщения в EventQueue и в итоге получит сообщение.

основной поток

Ваш фрагмент кода обычно находится в потоке main(),поток main можно рассматривать как своего рода worker thread здесь.Только вместо обновления графического интерфейса путем отправки сообщений в EventQueue он запускает графический интерфейс.В любом случае, инициацию можно рассматривать как тоже вид работы .

После инициализации GUI основной поток завершится, а EDT предотвратит выход из процесса.

И еще одно хорошее объяснение:

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

Интересная статья: Многопоточный инструментарий, несостоявшаяся мечта?

2 голосов
/ 05 февраля 2011

Это блок кода, который инструктируется выполнить позже (иногда называется deferred ). Внутренний класс (new Runnable() {...}) по сути позволяет вам передавать блок кода, который будет запущен. Метод invokeLater гарантирует, что блок кода будет запущен, но не гарантирует, когда. Иногда небезопасно запускать определенный код немедленно, и он слишком многословен, чтобы выполнять многопоточность самостоятельно. Так что Java предоставляет этот метод для безопасного запуска кода. Код будет запущен очень скоро, но только тогда, когда это будет безопасно.

1 голос
/ 03 мая 2011

Источник

Метод invokeLater () принимает объект Runnable в качестве параметра.Он отправляет этот объект в поток диспетчеризации событий, который выполняет метод run ().Вот почему метод run () всегда безопасен для выполнения кода Swing.

-IvarD

1 голос
/ 05 февраля 2011

Вызов invokeLater помещает указанный runnable в очередь для последующей обработки. То есть код внутри метода run() еще не будет запущен, когда вызов метода invokeLater вернется.

Существует два типичных варианта использования для этого типа кода.

  1. Текущий исполняемый код выполняется в фоновом потоке. Фоновые потоки не могут получить доступ к большей части свинг API. Подробнее о здесь . Если текущий поток уже является потоком пользовательского интерфейса, причина отсутствует, и вызов можно безопасно удалить.
  2. Текущий блок должен быть завершен, т.е. код достигает последней фигурной скобки. Это может привести к освобождению ресурсов и так далее. Это не так часто.

Анонимный класс передается в качестве параметра для вызова invokeLater. Он такой же, как этот код.

private void foo()
{
  java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
  public void run() {
    new NewJFrame().setVisible(true);
  }
}
...