Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX Task threads not terminating

I am writing a JavaFX application and my objects extend Task to provide concurrency away from the JavaFX GUI thread.

My Main class looks like this:

public class MainApp extends Application {

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));        
    Scene scene = new Scene(root);       
    stage.setScene(scene);
    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        public void handle(WindowEvent t) {
            //I have put this in to solve the threading problem for now.
            Platform.exit();
            System.exit(0);
        }
    });
    stage.show();
}

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

My GUI Controller Sample looks like this (abstracted slightly):

ExecutorService threadPool = Executors.newFixedThreadPool(2);
private void handleStartButtonAction(ActionEvent event) {
        MyTask task = new MyTask();
        threadPool.execute(task);
}

At the moment my task just does a sleep and prints numbers 1 through 10:

public class MyTask extends Task<String> {

@Override
protected String call() throws Exception {
    updateProgress(0.1, 10);
    for (int i=0;i<=10;i++) { 
        if (isCancelled()) {
            break;
        }
        Thread.sleep(1000);
        System.out.println(i);
        updateProgress(i, 10);  
    }  
    return "Complete";      
}
}

The problem I have is once the task completes it appears as though the thread the task is launched with continues to run. So when I exit the JavaFX application by pressing the "X" top right corner, the JVM continues to run and my application does not terminate. If you look at my main class, I have put in System.exit() which seems to solve the problem though I am aware this is not the correct way.

Can someone suggest what I need to do in terms of terminating my child threads, and what is the accepted way of doing this? i.e, checking they are complete and then terminated for example.

Thanks

like image 492
fixulate Avatar asked Mar 26 '14 09:03

fixulate


2 Answers

The Javadocs for Executors.newFixedThreadPool() state that:

The threads in the pool will exist until it is explicitly shutdown.

Also check the the usage examples of ExecutorService, they take care to always shutdown the pool.

You probably have to ensure that threadPool.shutdown() is called at the appropriate place of your application.

like image 79
Nikos Paraskevopoulos Avatar answered Sep 22 '22 06:09

Nikos Paraskevopoulos


The approach that Nikos provides (invoking shutdown) is good and straight-forward.

An alternate is to define your own thread factory for thread creation. In your thread factory, make the threads daemon threads. A JavaFX program stops when all non-daemon threads have completed (which means that your program will exit even if you don't explicitly shutdown the thread pool for your ExecutorService).

ExecutorService threadPool = Executors.newFixedThreadPool(
    2, 
    new ThreadFactory() {
        AtomicInteger a = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "mythread-" + a.getAndIncrement());
            t.setDaemon(true);
            return t;
        }
    }
);

Daemon threads aren't appropriate for all services, sometimes explicit shutdown handling is better.

The daemon thread factory approach is used in a few places in the JDK.

like image 36
jewelsea Avatar answered Sep 20 '22 06:09

jewelsea