saæ
saæ

Reputation: 183

Stop a sheduleAtFixedRate task in the ScheduledThreadPoolExecutor Java

Say I have this bloated example. What I would expect to happen is to get a couple of numbers in the console around three times, then I'd expect the "The task is stopped" line to be printed, and then I'd get no more numbers.

So I'd like to stop a task from being executed. So far I've tried to cancel(true) the future, executor.shutdownNow)( and executor.shutdown() the executor, but none of those lead to a behavior that I've described above. Am I missing something? Is there a way to cancel this task?

        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.setRemoveOnCancelPolicy(true);
        final int rareNumber = 302330233;
        ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
            int x = 0;
            while (true) {
                x++;
                if(x % rareNumber == 0) {
                    System.out.println(x);
                }
            }
        }, 1, 2, TimeUnit.SECONDS);
        Thread.sleep(3_000);
        // I'd like to stop a task here.
        System.out.println("The task is stopped");

Upvotes: 0

Views: 1090

Answers (3)

Michał Krzywański
Michał Krzywański

Reputation: 16910

There are a couple of things you should consider in your code :

  • You never shutDown your pool and threads in this pool are not Daemon Threads so if you create your Pool , the main JVM process will be prevented from shutting down - so you should close your pool. Shutting down the pool will interrupt the threads that are processing tasks. How to do it is described in ExecutorService docs :
void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }
  • If you want to make your task cancellable there are 2 common ways to do it :

    1. Check the Thread.currentThread().isInterrupted() status in a loop
    2. If you call some method that are blocking and can throw InterruptedException you can handle this exception. It will be thrown when the Thread is interrupted.
  • as you have set executor.setRemoveOnCancelPolicy(true); the Threads will not be be recreated if they are Interrupted. If you did not set this flag - it is a good idea to preserve the interruption status, as you are not the owner of those threads and you do not know what interruption means to them. But you are not using any methods that can throw InterruptedException so it is ok.

Upvotes: 1

Udith Gunaratna
Udith Gunaratna

Reputation: 2111

First, when you find a correct number at one execution, you should break that while loop to finish that execution cycle.

ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
    int x = 0;
    while (true) {
        x++;
        if(x % rareNumber == 0) {
            System.out.println(x);
            break;
        }
    }
}, 1, 2, TimeUnit.SECONDS);

Then you can cancel the future as follows to stop the fixed-rate scheduler.

    Thread.sleep(3_000);
    // I'd like to stop a task here.
    future.cancel(true);
    System.out.println("The task is stopped");

Upvotes: 1

František Hartman
František Hartman

Reputation: 15086

The correct method is executor.shutdownNow(). This causes the thread to be interrupted.

However your thread is not be waiting / sleeping at that time, so you don't get IterruptedException so you need to check Thread.intrrupted() flag:

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
    executor.setRemoveOnCancelPolicy(true);
    final int rareNumber = 302330233;
    ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
        int x = 0;
        while (true) {
            x++;
            if(x % rareNumber == 0) {
                System.out.println(x);
            }

            if (Thread.interrupted()) {
                return;
            }
        }
    }, 1, 2, TimeUnit.SECONDS);
    Thread.sleep(3_000);

    executor.shutdownNow();
    // I'd like to stop a task here.
    System.out.println("The task is stopped");

Upvotes: 1

Related Questions