SwingUtilities.invokeLater () зачем это нужно? - PullRequest
44 голосов
/ 24 августа 2010

Почему необходимо поместить код обновления графического интерфейса в SwingUtilities.invokeLater()?

Почему об этом не может позаботиться сам Swing?Почему вызывающий должен заботиться о том, как Swing обрабатывает обновления пользовательского интерфейса?

Ответы [ 7 ]

41 голосов
/ 24 августа 2010

Объекты Swing не безопасны для потоков . SwingUtilities.invokeLater() позволяет выполнить задачу в более поздний момент времени, как следует из названия; но что более важно, задача будет выполнена в потоке диспетчеризации событий AWT. При использовании invokeLater задача выполняется асинхронно; есть также invokeAndWait, который не вернется, пока не завершится выполнение задачи.

Некоторая информация о решении не делать потокобезопасным Swing можно найти здесь: Многопоточные наборы инструментов: несостоявшаяся мечта?

16 голосов
/ 24 августа 2010

Поскольку обновления GUI должны выполняться в потоке диспетчеризации событий. Если вы работаете в другом потоке, обновление в invokeLater возвращает его из вашего потока в поток событий.

Более подробное объяснение здесь: http://www.oracle.com/technetwork/java/painting-140037.html

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

8 голосов
/ 24 августа 2010

Качели однопоточные. Каждое обновление пользовательского интерфейса должно происходить из так называемого EDT - потока диспетчера событий, который является основным потоком GUI, который использует Swing (и я думаю, AWT). Если вы этого не сделаете, тогда могут или будут происходить странные вещи (хотя мне здесь больше нравятся Windows FOrms, которые просто выдают исключение, если вы делаете это неправильно).

При этом вам не нужно заключать каждую операцию пользовательского интерфейса в SwingUtilities.invokeLater() - если код, который вы пишете, уже выполняется EDT, это не нужно. Так что ActionListener для нажатия кнопки это не нужно. Но слушатель внешнего объекта, запущенный в каком-то другом потоке, обновляет где-то JLabel - там вам это нужно.

5 голосов
/ 24 августа 2010

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

См. Одновременный в Swing из руководства по Java для получения более подробной информации. В нем также упоминается эта запись в блоге о том, почему сложно написать многопоточный инструментарий GUI.

3 голосов
/ 24 августа 2010

Вся окраска компонентов должна выполняться в один поток, поэтому они отображаются правильно. Таким образом, компонент будет знать, какая часть уже нарисована, а какая нет.

Если вы вызываете связанный с «рисованием» метод (paint, update, paintComponent, show, setVisible, pack и т. Д.) Вне EDT, вы будете пытаться рисовать в двух разных потоках, и это может вызвать проблемы.

Когда вам нужно использовать другой поток для обновления пользовательского интерфейса, вы должны вызвать его с помощью средства invokeLater, которое, в свою очередь, поместит его в EDT для вас, так что вы все равно будете рисовать в том же потоке.

Вам не нужно его использовать, если вы кодируете в методе, который уже выполняется в EDT (например, actionPerformed или paint или в одном из них), или если вы выполняете код, а не пользовательский интерфейс связанные (например, обработка файлов в фоновом режиме и т. д.)

Чтобы лучше понять все эти понятия, прочитайте: Правило одного потока

2 голосов
/ 24 августа 2010

SwingUtilities.invokeLater ()

Вызывает асинхронное выполнение doRun.run () в потоке диспетчеризации событий AWT. Это произойдет после обработки всех ожидающих событий AWT. Этот метод следует использовать, когда поток приложения должен обновить графический интерфейс.
...

1 голос
/ 24 августа 2010

Повторение других: Swing не является потокобезопасным, поэтому один поток должен выполнять все обновления, чтобы избежать проблем параллелизма.invokeLater - это служебный метод для выполнения чего-либо внутри потока обработки событий.

Почему Swing не делает это внутренне: это мое впечатление ... Я думаю, потому что это было бы излишним -проверить каждое место, где происходит обновление.Это раздуло бы код Swing, затруднило бы проверку и удобство сопровождения кода.

С другой стороны, приложению не так сложно узнать, не выполняется ли оно внутри потока GUI, и вызвать invokeLater.Это будет, когда собственное приложение запустит какой-то поток раньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...