Как остановить "JavaFX Application Thread"
У меня есть простое консольное приложение, которое иногда нужно выполнять графические операции, для тех, у кого я использую фреймворк JavaFx (есть некоторые функции, которые мне нужны, как стиль CSS для текста)
Я просто генерирую некоторые фигуры и текст в скрытую сцену, а затем сохраняю их в файле и все,
Я знаю, что для работы с JavaFx мне нужно передать графические операции в поток JavaFx, но когда все будет готово, и я должен закрыть приложение (через несколько часов), этот поток JavaFx по-прежнему остается открытым... и я действительно не хотите принудительно выходить с System.exit(), потому что если что-то заблокировано, я могу знать/ждать (ТАКЖЕ, я не хочу выполнять все как приложение JavaFx (поскольку компоненты JavaFx составляют менее 1% от моего основное приложение)
код очень прост и googling вокруг Я нашел только использовать
Platform.exit();
который, похоже, не работает, я также пробовал играть с такими параметрами платформы, как
Platform.setImplicitExit(false);
вот мое тестовое приложение, которое вы можете запустить:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Pos;
import javafx.scene.layout.VBox;
public class SOTestFX {
public static void main(String[] args) {
SOTestFX t = new SOTestFX();
t.runFxThread();
}
public void runFxThread(){
//Application.launch(args);
final JFXPanel jfxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
@Override
public void run() {
System.err.println("CREATING IMAGE");
simpleFXoperations();
System.err.println("NOW CALL EXIT");
System.err.println("JAVA FX THREAD SHOULD BE EXITED NOW");
Platform.exit();
}
});
try {
Thread.sleep(3000); // just wait a bit if something should happen, let it happen..
} catch (InterruptedException e) {
e.printStackTrace();
}
//jfxPanel.removeNotify(); // return -> java.lang.NullPointerException
//Platform.exit(); // -> does nothing
System.err.println("i will never die!");
}
public void simpleFXoperations(){
VBox vbox1 = new VBox();
vbox1.setAlignment(Pos.BOTTOM_CENTER);
vbox1.setStyle("-fx-border-style: solid;"
+ "-fx-border-width: 1;"
+ "-fx-border-color: white");
System.err.println("simpleFXoperations() _DONE");
}
}
и это нить, которая никогда не закрывается
"Прикрепить прослушиватель" - Тема t @17 java.lang.Thread.State: RUNNABLE
Заблокированные управляемые синхронизаторы: - Нет
"Тема приложения JavaFX" - Тема t @13 java.lang.Thread.State: RUNNABLE на com.sun.glass.ui.gtk.GtkApplication._runLoop (родной Метод) при com.sun.glass.ui.gtk.GtkApplication $3 $1.run(GtkApplication.java:82) в java.lang.Thread.run(Thread.java:722)
Заблокированные управляемые синхронизаторы: - Нет
Обновление: Я использую новейший Oracle JDK 7u17 64bit на Linux Fedora 16 64bit.
Ответы
Ответ 1
Fix:
Мне удалось исправить эту проблему, вызвав com.sun.javafx.application.PlatformImpl.tkExit()
непосредственно перед Platform.exit()
. Я не очень хорошо понимаю источник JavaFX, но, похоже, он работает; YMMV.
Обновление: Выполнение этого в Java 8 приведет к предупреждению, вы можете просто отключить предупреждение с помощью @SuppressWarnings("restriction")
. Это не должно быть проблемой.
Объяснение:
Я понял это, копая исходный код; JFXPanel
имеет этот небольшой фрагмент (это от JavaFX 2.2.25)
finishListener = new PlatformImpl.FinishListener() {
public void idle(boolean paramAnonymousBoolean) {
if (!JFXPanel.firstPanelShown) {
return;
}
PlatformImpl.removeListener(JFXPanel.finishListener);
JFXPanel.access$102(null);
if (paramAnonymousBoolean)
Platform.exit();
}
public void exitCalled()
{
}
Проблема в том, что если вы используете только немного JavaFX в своем приложении, то метод idle(boolean)
никогда ничего не делает (потому что firstPanelShown == false
), что предотвращает удаление слушателя, что предотвращает JavaFX Toolkit
от выключения... что означает, что вы должны отключить его вручную.
Ответ 2
Ваша основная функция не принадлежит объекту JavaFx Application, и я думаю, что ваша программа никогда не запустит цикл потока приложений.
Кажется, вам следует:
public class SOTestFX extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// Do stuff here to show your stage or whatever you want;
// This will be called on the JavaFX thread
}
}
Ответ 3
Это скользкая ситуация, поскольку (насколько я понимаю) цель потока JavaFX заключается в прозрачном использовании различных аппаратных конвейеров. Могу ли я предложить разместить ваши запросы JavaFX в отдельный, ссылающийся, проект; и сохранить все остальное, включая ваш основной метод, в другом? Это всегда срабатывало для меня.
В принципе, бизнес-логика и модель идут в одном проекте, а просмотр и управление (как правило, основанные на JavaFX) идут в другом. Это позволяет осуществлять независимое завершение потока JavaFX. Надеюсь, это применимо к тому, что вы пытаетесь сделать.
Ответ 4
Я пробовал много всего, потому что ни один из вышеперечисленных ответов не работал у меня.
Лучше всего для меня просто закрыть все JVM, используя
System.exit(1);
поскольку все мое приложение - это то, что одно приложение JavaFX и поэтому может быть отключено при закрытии этапа.
1 в моем случае является просто случайным int.