Является ли метод Swing repaint() все еще безопасным для использования вне EDT в Java 7+?
Я знаю, что раньше звонить считалось безопасным repaint()
и несколько других выбранных методов из любого потока, даже с потоковой моделью Swing, однако мне недавно сказали в комментарии, что это не так.
Google нашел много старых сообщений о том, что это безопасно, но в последнее время ничего. Все официальные ссылки, в которых говорилось, что это безопасно, похоже, исчезли, и я нашел несколько человек на разных форумах, обсуждающих, как это больше не безопасно.
Я не могу найти ничего официального, чтобы подтвердить, действительно ли это или нет - и я действительно хотел бы видеть что-то, объясняющее логику изменения, если оно было изменено. Учитывая, насколько сильно это может привести к поломке существующих приложений, кажется, что удалить очень странную функцию.
На самом деле я ищу ссылку на официальную ссылку (например, Javadoc, oracle tutorial или ссылку на исходный код), в которой указано, являются ли эти методы безопасными для вызова из какого-либо потока.
Для справки этот вопрос здесь:
Безопасно ли использовать Component.repaint() вне EDT?
Дает цитату из недавно исчезнувшей страницы Sun, в которой говорится:
Следующие методы JComponent безопасны для вызова из любого потока: repaint(), revalidate() и invalidate(). Методы repaint () и revalidate () ставят в очередь запросы к потоку диспетчеризации событий для вызова paint () и validate () соответственно.
Это соответствует моему пониманию, но я не могу найти эту страницу или любую аналогичную страницу сейчас, и я видел неподтвержденные слухи от нескольких людей, которые говорили, что это больше не безопасно. Но с другой стороны, я не могу найти ничего определенного, говоря, что эта функция изменилась.
Изменить заметки
Что может помочь решить этот вопрос, так это официальное заявление от Oracle об изменениях в обработке потоков Swing. Я нашел страницу "Изменения в Java 7", но она вообще не упоминала об этом, ни одна из этих страниц никоим образом не упоминает многопоточность или EDT:
http://docs.oracle.com/javase/7/docs/technotes/guides/swing/enhancements-7.html
http://docs.oracle.com/javase/7/docs/technotes/guides/awt/enhancements-7.html
3 ответа
Это официальная ссылка:
Политика потоков Swing
В общем, Swing не является потокобезопасным. Все компоненты Swing и связанные с ними классы, если не указано иное, должны быть доступны в потоке диспетчеризации событий.
И repaint
Метод не "документирует иначе".
Чтобы вдвойне заверить вас в том, что вам не нужно искать более подробный ответ, чем Javadoc отдельного метода, посмотрите, например, как безопасность потока метода была задокументирована в Java 6 Javadoc.
Обновить
По-видимому, необходимы дополнительные разъяснения относительно различия между нормативной спецификацией, описательными техническими статьями и деталями любой конкретной реализации. Что заявляет Javadoc: нет никакой гарантии, что repaint
это потокобезопасный метод. Кстати, часто обсуждаемое в Java 7 решение об удалении "многопоточного" обозначения из большей части Swing API заключалось лишь в следующем: изменение договора, а не реализация.
Конкретная реализация repaint
в OpenJDK 7 представляется поточно-ориентированным, что не имеет ничего общего с гарантиями, данными в спецификации. Код, который опирается на безопасность потока repaint
или другие методы не работают и не гарантируется правильное поведение во всех реализациях Java.
Как обсуждено в Живописи в AWT и Swing: Обработка краски,
JComponent.repaint()
регистрирует асинхронный запрос на перерисовку для компонентаRepaintManager
, который используетinvokeLater()
поставить в очередьRunnable
чтобы позже обработать запрос в потоке диспетчеризации событий.
Это необходимое, но не достаточное условие для установления отношения " до того, как произойдет", между последовательными вызовами repaint()
, На практике вам все равно нужно синхронизировать доступ к любым данным, которые совместно используются потоками. Без этого невозможно обеспечить видимость любых изменений, которые могут повлиять на последующий вызов repaint()
,
Я бы сказал, что это все еще потокобезопасно. Метод repaint() не меняет свойства любого компонента Swing.
Метод repaint() вызывает RepaintManager. RepaintManager затем (потенциально) объединит несколько запросов рисования в один запрос рисования. Затем он добавит запрос краски в EDT для обработки.