2016-02-04 2 views
0

Интересно, есть ли какой-нибудь аккуратный и чистый способ отключения исполнителей потоков приложения, когда основное окно закрывается.Завершение потоков JavaFX при выходе приложения

Если потоки отмечены как потоки демона, они автоматически прерываются, когда приложение закрывается. Но в моем случае я не хочу этого делать. если задание записывает файл, я хочу, чтобы задача завершилась, и поток был остановлен только после завершения задачи, иначе я закончил с поврежденным файлом.

Возможное решение может использовать каждый исполнитель только один раз и вызывать его завершение после отправки задачи, но у этого есть накладные расходы на создание нового потока каждый раз, когда должна быть отправлена ​​новая задача.

В моем текущем приложении, имеющем только один контроллер, я использую событие onClose главного окна, чтобы вызвать метод в контроллере для выключения исполнителя, если он есть (код ниже). Но это не чистое решение, если есть много контроллеров.

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

Может ли кто-нибудь разработать лучший?

+0

Если есть много контроллеров, не должны они одни и те же исполнителя в любом случае ? –

+0

Хорошая точка @James_D, но я спрашиваю, что, если мне нужно больше одного. Как только я придумал ужасное приложение, которое использовало пул потоков для загрузки данных из нескольких URL-адресов, но для записи результатов потребовалось только один поток, или это испортило бы их последовательность. –

ответ

2

Переопределить 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); 
    } 
} 

(Очевидно, что вам нужно реорганизовать, что если у вас есть исполнитель в другом классе, но идея в основном то же самое.)

+1

Это почти то же самое, что я делаю althoug немного лучше. Но что, если в конечном итоге у меня будет несколько исполнителей в нескольких контроллерах и субконтроллерах? Это можно сделать, когда каждый контроллер отключается, и это субконтроллеры, но есть ли лучший способ ...? –

+0

Обычно у меня на каждом контроллере есть один и тот же исполнитель; вид точки исполнителя заключается в том, что это централизованный механизм обработки пула потоков. (Обычно мой исполнитель является частью службы, связанной с моделью, и модель разделяется контроллерами и т. Д.). Затем я вызываю метод shutdown в службе (или модели, в зависимости от деталей архитектуры). –

+0

Да, возможно, создание моей собственной фабрики-исполнителя, которая следит за исполнителями, которых мне в конечном итоге понадобится, и зная, как их закрыть, будет самым аккуратным способом. Спасибо. –

Смежные вопросы