简体   繁体   中英

is there an option to cancel a task in ScheduledExecutorService?

I am writing an application on javaFX and as a part of my view(in MVVM architecture) I am using an FXML Label for the status of my application to present for the client(for example: if a file was uploaded successfully or not).

I want to clean this status label a few seconds after an update was made.

I used this code to run a thread to do so but the problem occurs when more than one update was made before the previous finished its job.

I thought of canceling any previous threads in the thread-pool before executing a new thread but I didn't find a way to do so.

public class MainWindowController implements Observer {

    ViewModel vm;
    ScheduledExecutorService scheduledExecutorService;
    Stage stage;
    @FXML
    Label appStatus;

    public void loadProperties(){
        FileChooser fc = new FileChooser();
        fc.setTitle("Load Project Properties");
        fc.setInitialDirectory(new File("./resources"));
        FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
                "XML Files (*.xml)", "*.xml");
        fc.getExtensionFilters().add(extensionFilter);
        File chosenFile = fc.showOpenDialog(stage);

        //CONTINUE HERE
        if(chosenFile==null){
            appStatus.setTextFill(Color.RED);
            vm.appStat.setValue("Failed to load resource");
        }
        else{
            vm.setAppProperties(chosenFile.getAbsolutePath());
        }
        cleanStatusBox();

    }

    public void cleanStatusBox(){
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                Platform.runLater(()->vm.appStat.setValue(""));
            }
        },10000, TimeUnit.MILLISECONDS);
    }

    public void setViewModel(ViewModel vm) {
        this.vm = vm;
        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        appStatus.textProperty().bind(vm.appStat);
    }
}

A ScheduledExecutorService (and using background threads in general) is far too heavy-handed an approach for this.

Instead, consider using a PauseTransition , which once started will execute its onFinished handler on the JavaFX Application Thread after the specified time. The playFromStart() method "restarts" the pause, enabling multiple updates without conflict.

public class MainWindowController implements Observer {

    ViewModel vm;
    PauseTransition clearLabelPause;
    Stage stage;
    @FXML
    Label appStatus;

    public void loadProperties(){
        FileChooser fc = new FileChooser();
        fc.setTitle("Load Project Properties");
        fc.setInitialDirectory(new File("./resources"));
        FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
                "XML Files (*.xml)", "*.xml");
        fc.getExtensionFilters().add(extensionFilter);
        File chosenFile = fc.showOpenDialog(stage);

        //CONTINUE HERE
        if(chosenFile==null){
            appStatus.setTextFill(Color.RED);
            vm.appStat.setValue("Failed to load resource");
        }
        else{
            vm.setAppProperties(chosenFile.getAbsolutePath());
        }
        clearLabelPause.playFromStart();

    }

    

    public void setViewModel(ViewModel vm) {
        this.vm = vm;
        clearLabelPause = new PauseTransition(Duration.seconds(10));
        clearLabelPause.setOnFinished(e -> vm.appStat.setValue(""));
        appStatus.textProperty().bind(vm.appStat);
    }
}

The schedule method returns a ScheduledFuture which has a cancel method. You are currently discarding that.

Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

After this method returns, subsequent calls to isDone() will always return true. Subsequent calls to isCancelled() will always return true if this method returned true.

In your case, if the task hasn't started then it will be removed from the queue of tasks, and it will be as if you never scheduled it.

If the task is currently running then you will not be able to cancel it, since you do not check the thread's interrupt flag. Whether you pass true or false to cancel() will not make a difference.

All your task does is push a task onto another thread, so the scheduled executor task is likely to be extremely quick. Because of that, it doesn't really matter that you don't check the interrupt flag. For longer running tasks which involve more steps - do X, then Y, then Z - then it would be important to check the flag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM