The code below doest not exit properly when I close the application. I believe the issue is where do i exactly call the system.exit and platform.exit....
关闭应用程序时,下面的代码无法正常退出。我相信问题是我在哪里完全调用system.exit和platform.exit ....
hour_Label.textProperty().bind(hour);
minute_Label.textProperty().bind(minute);
second_Label.textProperty().bind(second);
new Thread(() ->
{
for (;;)
{
try
{
final SimpleDateFormat simpledate_hour = new SimpleDateFormat("h");
final SimpleDateFormat simpledate_minute = new SimpleDateFormat("mm");
final SimpleDateFormat simpledate_second = new SimpleDateFormat("s");
Platform.runLater(new Runnable() {
@Override public void run()
{
hour.set(simpledate_hour.format(new Date()));
minute.set(simpledate_minute.format(new Date()));
second.set(simpledate_second.format(new Date()));
}
});
Thread.sleep(200);
}
catch (Exception e){logger.warn("Unexpected error", e); Thread.currentThread().interrupt(); Platform.exit(); System.exit(0);}
}
}).start();
2 个解决方案
#1
Don't use threads! Use a Timeline
instead:
不要使用线程!改为使用时间轴:
Timeline clock = new Timeline(
new KeyFrame(Duration.seconds(0), evt -> {
LocalTime now = LocalTime.now();
hour.set(String.format("%d", now.getHour()));
minute.set(String.format("%02d", now.getMinute()));
second.set(String.format("%d", now.getSecond()));
}),
new KeyFrame(Duration.seconds(1))
);
clock.setCycleCount(Animation.INDEFINITE);
clock.play();
As a Timeline
is run by the FX Application Thread, you don't need any synchronization via Platform.runLater(...)
. Apart from that, you can start and stop the timeline as desired, and it automatically terminates when the FX Application Thread stops.
由于时间轴由FX应用程序线程运行,因此您无需通过Platform.runLater(...)进行任何同步。除此之外,您可以根据需要启动和停止时间线,并在FX应用程序线程停止时自动终止。
#2
Make your thread a daemon thread.
使您的线程成为守护程序线程。
The Java Virtual Machine exits when the only threads running are all daemon threads.
当运行的唯一线程都是守护程序线程时,Java虚拟机将退出。
You also need to let the thread know that it should exit.
你还需要让线程知道它应该退出。
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
public class Sleeper extends Application{
@Override
public void start(Stage stage) throws Exception {
Label time = new Label();
AtomicBoolean shuttingDown = new AtomicBoolean(false);
Thread thread = new Thread(() -> {
while (!shuttingDown.get() && !Thread.interrupted()) {
Platform.runLater(() -> time.setText(new Date().toString()));
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread.setDaemon(true);
thread.start();
Button exit = new Button("Exit");
exit.setOnAction(event -> {
shuttingDown.set(true);
thread.interrupt();
Platform.exit();
});
stage.setScene(new Scene(new StackPane(time), 240, 40));
stage.show();
}
}
You don't need to invoke Platform.exit() or System.exit(0) in an exception handler of your thread.
您不需要在线程的异常处理程序中调用Platform.exit()或System.exit(0)。
You may find it more convenient to use a JavaFX Task. The task documentation explains methods of canceling a task.
您可能会发现使用JavaFX Task更方便。任务文档说明了取消任务的方法。
But really, I wouldn't advise using another thread at all for your example, instead use a Timeline as exemplified in Sergey's five second wonder in his answer to: JavaFX periodic background task.
但实际上,我不会建议您使用另一个线程作为您的示例,而是使用时间轴,例如谢尔盖在他的回答中的五秒奇迹:JavaFX定期后台任务。
#1
Don't use threads! Use a Timeline
instead:
不要使用线程!改为使用时间轴:
Timeline clock = new Timeline(
new KeyFrame(Duration.seconds(0), evt -> {
LocalTime now = LocalTime.now();
hour.set(String.format("%d", now.getHour()));
minute.set(String.format("%02d", now.getMinute()));
second.set(String.format("%d", now.getSecond()));
}),
new KeyFrame(Duration.seconds(1))
);
clock.setCycleCount(Animation.INDEFINITE);
clock.play();
As a Timeline
is run by the FX Application Thread, you don't need any synchronization via Platform.runLater(...)
. Apart from that, you can start and stop the timeline as desired, and it automatically terminates when the FX Application Thread stops.
由于时间轴由FX应用程序线程运行,因此您无需通过Platform.runLater(...)进行任何同步。除此之外,您可以根据需要启动和停止时间线,并在FX应用程序线程停止时自动终止。
#2
Make your thread a daemon thread.
使您的线程成为守护程序线程。
The Java Virtual Machine exits when the only threads running are all daemon threads.
当运行的唯一线程都是守护程序线程时,Java虚拟机将退出。
You also need to let the thread know that it should exit.
你还需要让线程知道它应该退出。
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
public class Sleeper extends Application{
@Override
public void start(Stage stage) throws Exception {
Label time = new Label();
AtomicBoolean shuttingDown = new AtomicBoolean(false);
Thread thread = new Thread(() -> {
while (!shuttingDown.get() && !Thread.interrupted()) {
Platform.runLater(() -> time.setText(new Date().toString()));
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread.setDaemon(true);
thread.start();
Button exit = new Button("Exit");
exit.setOnAction(event -> {
shuttingDown.set(true);
thread.interrupt();
Platform.exit();
});
stage.setScene(new Scene(new StackPane(time), 240, 40));
stage.show();
}
}
You don't need to invoke Platform.exit() or System.exit(0) in an exception handler of your thread.
您不需要在线程的异常处理程序中调用Platform.exit()或System.exit(0)。
You may find it more convenient to use a JavaFX Task. The task documentation explains methods of canceling a task.
您可能会发现使用JavaFX Task更方便。任务文档说明了取消任务的方法。
But really, I wouldn't advise using another thread at all for your example, instead use a Timeline as exemplified in Sergey's five second wonder in his answer to: JavaFX periodic background task.
但实际上,我不会建议您使用另一个线程作为您的示例,而是使用时间轴,例如谢尔盖在他的回答中的五秒奇迹:JavaFX定期后台任务。