6

Is there a built-in way to cancel a Runnable task that has been scheduled at a fixed rate via ScheduledExecutorService.scheduleAtFixedRate and await it's completion if it happens to be running when cancel is called?.

Consider the following example:

public static void main(String[] args) throws InterruptedException, ExecutionException  {

    Runnable fiveSecondTask = new Runnable() {
        @Override
        public void run() {
            System.out.println("5 second task started");
            long finishTime = System.currentTimeMillis() + 5_000;
            while (System.currentTimeMillis() < finishTime);
            System.out.println("5 second task finished");
        }
    };

    ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture<?> fut = exec.scheduleAtFixedRate(fiveSecondTask, 0, 1, TimeUnit.SECONDS);

    Thread.sleep(1_000);
    System.out.print("Cancelling task..");
    fut.cancel(true);

    System.out.println("done");
    System.out.println("isCancelled : " + fut.isCancelled());
    System.out.println("isDone      : " + fut.isDone());
    try {
        fut.get();
        System.out.println("get         : didn't throw exception");
    }
    catch (CancellationException e) {
        System.out.println("get         : threw exception");
    }
}

The output of this program is:

5 second task started
Cancelling task..done
isCancelled : true
isDone      : true
get         : threw exception
5 second task finished

Setting a shared volatile flag seems the simplest option, but I'd prefer to avoid it if possible.

Does the java.util.concurrent framework have this capability built in?

hendalst
  • 2,957
  • 1
  • 24
  • 25
  • what Exception is thrown? add `e.printStackTrace()` in `catch` block. – Braj May 03 '14 at 07:48
  • @Braj a `CancellationException` is thrown, as documented in the API. The example program above was testing whether the exception is thrown immediately after calling `cancel` or after calling `cancel` and the task actually completing. – hendalst May 03 '14 at 08:24

1 Answers1

0

I am not entirely sure what are you trying to achieve but as I went here from google search I thought It may be worth responding to your question.

1) If you want to forcibly stop heavy workload - unfortunately it seems there is no solution for it(when thread does not respond to interrupts). Only way of dealing with it would be to insert Thread.sleep(1) in between time consuming operations in your loop (http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html) - maybe deamon thread would help here but I really discourage using them.

2) If you want to block current thread until the child thread finishes then instead of calling cancel you can use get http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get() or even get with timeout.

3) If you want clean cancel of subthread then you can call:

fut.cancel(false);

this will not interrupt current execution but will not schedule it to run again.

4) If your workload is not heavy and you only need to wait for 5 seconds then use thread sleep or TimeUnit sleep. In such case interrupt / cancel will be immediate.

Also your example lacking shutdown call on Executor which cause application does not stop.

JJ Roman
  • 4,225
  • 1
  • 27
  • 21