应用程序退出后,JavaFX线程关闭

时间:2016-02-04 17:59:53

标签: javafx javafx-8

我想知道在主窗口关闭时是否有任何干净利落的关闭应用程序线程执行程序的方法。

如果线程被标记为守护程序线程,则它们会在应用程序关闭时自动中断。但就我而言,我不想这样做。如果一个任务正在编写一个文件,我希望任务完成,并且线程只在任务完成后关闭,otehrwise我最终得到了一个损坏的文件。

一个可能的解决方案可能是在提交任务后仅使用每个执行程序一次并在其上调用shutdown,但是每次提交新任务时都需要创建新线程的开销。

在我当前只有一个控制器的应用程序中,我使用主窗口的onClose事件来调用控制器中的方法来关闭执行程序(如果有的话)(下面的代码)。但如果有很多控制器,这不是一个干净的解决方案。

MainController controller = loader.getController();
stage.setOnCloseRequest(ev -> {
    controller.finalize();
});

任何人都可以设计出更好的产品吗?

1 个答案:

答案 0 :(得分:3)

覆盖stop并在执行服务上调用shutdown;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class CleanExecShutdown extends Application {

    private ExecutorService exec ;
    private int count ;

    @Override
    public void start(Stage primaryStage) {
        exec = Executors.newCachedThreadPool();
        ListView<String> completedTasks = new ListView<>();
        Button button = new Button("Start new task");
        Random rng = new Random();
        button.setOnAction(e -> {
            final int n = ++count;
            Task<String> task = new Task<String>() {
                @Override
                public String call() {
                    try {
                        Thread.sleep(rng.nextInt(1000)+1000);
                    } catch (InterruptedException exc) {
                        exc.printStackTrace();
                        Thread.currentThread().interrupt();
                    }
                    String message = "Task "+n+" completed";
                    System.out.println(message);
                    return message ;
                }
            };
            task.setOnSucceeded(evt -> completedTasks.getItems().add(task.getValue()));
            exec.execute(task);
        });

        BorderPane root = new BorderPane();
        root.setCenter(completedTasks);
        BorderPane.setAlignment(button, Pos.CENTER);
        BorderPane.setMargin(button, new Insets(5));
        root.setBottom(button);
        Scene scene = new Scene(root, 250, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    @Override
    public void stop() {
        if (exec != null) {
            exec.shutdown();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

(显然你需要重构一下,如果你的执行者在另一个班级,但这个想法基本相同。)