Объясните, что делает следующий код?

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

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

Ответы

Ответ 1

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

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

Ответ 2

Однопоточная модель и EDT

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

В Swing сам поток, который обслуживает single-thread-model, называется Event Dispatching Thread, то есть EDT. Свинг не предоставляется. Он предоставляется Аннотация Window Toolkit, то есть AWT.

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

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

java.awt.EventQueue

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

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

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

После запуска графического интерфейса основной поток выйдет, и EDT не позволит процессу выйти из него.

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

Обсуждение событий Java-Dispatching Thread

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

Ответ 3

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

Ответ 4

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

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

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

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

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

Ответ 5

Источник

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

-IvarD