13

When I create a thread by calling ScheduledExecutorService.schedule(), it never terminates after executing the scheduled task.

For example the following program never quits:

public static void main(String[] args) {
  ScheduledFuture scheduledFuture = 
      Executors.newSingleThreadScheduledExecutor().schedule(new Callable() {

    public Void call() {
      doSomething();
      return null;
    }

  }, 1, TimeUnit.SECONDS);
}

public static void doSomething() {
}

Is this a JDK bug, or did I just miss something?

oberlies
  • 11,503
  • 4
  • 63
  • 110
moonese
  • 483
  • 1
  • 6
  • 15

3 Answers3

7

A scheduled task is either being executed or is waiting to be executed.

If the task is waiting to be executed, future.cancel() will prevent it from being executed (both cancel(true)/cancel(false)).

If the task is already being executed, future.cancel(false) will have no effect. future.cancel(true) will interrupt the thread that is executing that task. Whether this will have any effect is up to you, who will implement that task. A task may or may not respond to interruption depending on the implementation.

In order to make your task responsive to cancellation, you must implement doSomething() so that it will respond to interruption.

There are basically two way to do this:

1.Check interruption flag in your logic

public void doSomething(){
    stuff();
    //Don't use Thread.interrupt()
    if(Thread.currentThread().isInterrupted()){
        // We have an interruption request, possibly a cancel request
        //Stop doing what you are doing and terminate.
        return;
    }
    doLongRunningStuff();
}  

You must occasionally check for the interruption flag, and if interrupted, stop what you are doing and return. Be sure to use Thread.isInterrupted() and not Thread.interrupt() for the check.

2.Act upon Interrupted exception

public void doSomething(){
    try{
        stuff();
    }catch(InterruptedException e){
        // We have an interruption request, possibly a cancel request

        // First, preserve Interrupted Status because InterruptedException clears the 
        // interrupted flag
        Thread.currentThread.interrupt();

        // Now stop doing your task and terminate
        return;
    }

    doLongRunningStuff();
}

When you have any method that throws InterruptedException, be sure to stop what you doing and terminate when one is thrown.

Once you implement your methods in this way, you can call future.cancel(true) to cancel the execution of a running task.

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
  • How to shutdown the schedule after command is called? So as to release thread resource. After all, the task created by schedule executes once. – Nickolas Oct 08 '13 at 11:54
  • @Nickolas: Not sure what you mean, but if you mean a task that was scheduled to run once (after a delay etc) AND it has already completed, then the task would have already stopped (and released the thread). Otherwise my answer still applies. – Enno Shioji Oct 08 '13 at 12:50
  • 1
    This is a nice answer but to a different question. The problem is not how to terminate the task - the OP explicitly states that the task is a nop - but how to terminate the thread used to run the task. – oberlies Apr 29 '14 at 16:36
5

Your program never terminates because you create a ScheduledExecutorService, which holds a thread pool, but you never shut down the service. Therefore, the user threads in the thread pool are never terminated, and hence the VM keeps running forever.

To solve this problem, you need to call a shutdown() on the executor service. This can even be done directly after scheduling the task you want to execute:

public static void main(String[] args) {
  ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
  ScheduledFuture scheduledFuture = executorService.schedule(new Callable() {

    public Void call() {
      doSomething();
      return null;
    }

  }, 1, TimeUnit.SECONDS);
  executorService.shutdown();
}

This will execute the scheduled task normally and then terminate the thread in the pool.

oberlies
  • 11,503
  • 4
  • 63
  • 110
1

You need to call scheduledExecutorService.shutdown() to stop the execution. Otherwise it is restarted every second.

(EDITED: see comments)

Georg Leber
  • 3,470
  • 5
  • 40
  • 63
  • 2
    Should call scheduledExecutorService.shutdown() instead of scheduleFuture.shutdown(), and ScheduledExecutorService.schedule() call is one-shot action, that will never be restarted again. – moonese May 25 '10 at 09:29