Почему Platform.runLater не проверяет, находится ли он в данный момент в потоке JavaFX?
При использовании JavaFX 8 нам нужно запускать взаимодействия с GUI через Platform.runLater
, иначе они будут генерировать исключения, если они запускаются из другого потока.
Однако реализация Platform.runLater
никогда не проверяет, находится ли она в данный момент в потоке JavaFX.
Я написал следующий метод:
public static void runSafe(final Runnable runnable) {
Objects.requireNonNull(runnable, "runnable");
if (Platform.isFxApplicationThread()) {
runnable.run();
}
else {
Platform.runLater(runnable);
}
}
Это гарантирует, что он никогда не может быть запущен в потоке не-fx-приложения.
Есть ли причина, по которой реализация по умолчанию не делает такого рода короткое замыкание?
Ответы
Ответ 1
runLater
по существу помещает ваш Runnable в очередь для выполнения, когда поток FX доступен. Доступ к методу можно получить через потоки без FX. Представьте себе, что некоторые другие потоки поставили задачи в очередь runLater
, а затем снова вызвали runLater
, будь то из потока FX или нет, должны поместить новую задачу в хвост этой очереди.
При коротком замыкании вы предлагаете, чтобы предыдущие задачи в основном имели более низкий приоритет, который может быть нежелательным.
Ответ 2
При вызове функции, и функция называется "runLater", я ожидаю, что она будет запущена позже, а не сейчас.
Мне кажется, что реализация правильная, основанная на ней имя и документация:
Запустите указанный Runnable в приложении JavaFX Application Thread в какое-то неопределенное время в будущем.
Этот метод, который может быть вызван из любого потока, отправит Runnable в очередь событий, а затем немедленно возвращается к вызывающему. Runnables выполняются в том порядке, в котором они размещены. Пробег, переданный в метод runLater, будет выполнен до того, как любой Runnable передаст последующий вызов runLater
Если вы не хотите, чтобы код запускался позже, не просите, чтобы он запускался позже. Это то, что вы по существу сделали с вашим кодом.
Ответ 3
Я видел, как люди, звонящие EventQueue.invokeLater
из EDT в Swing иногда... это, согласно канону, законная техника. Итак, это та же ситуация в JavaFX, если я не ошибаюсь.
У меня лично есть свои сомнения по поводу этой техники. См. этот вопрос: выбранный ответ использует invokeLater
, потому что selectAll()
должен иметь все текущие события EDT до того, как он будет вызван: это решение действительно гарантирует, что selectAll
не может быть запущен перед другим кодом EDT, который здесь происходит.
Но этот ответ, я утверждаю, имеет уязвимости. См. Ответ, который я предложил (написанный на Jython, но должен быть понятным). Предположим, что кто-то устанавливает "подсчет щелчка, чтобы начать редактирование" до 1. Предположим, что более тревожно, что что-то непредсказуемое происходит между invokeLater
и selectAll
. Если вы абсолютно не уверены, что у вас вообще нет альтернативного механизма, или абсолютно уверены, что события и объекты этих двух потоков полностью "отсоединены", я бы сказал, что не позволю runLater
из потока JavaFX.
Concurrency всегда ждет, чтобы укусить вас. Лучше всего использовать такие методы с особой осторожностью, поэтому!