Future.cancel() method is not working
Asked Answered
M

2

5

The code that I have creates a Callable instance and using ExecutorService a new thread is being created. I want to kill this thread after certain amount of time if the thread is not done with its execution. After going through the jdk documentation I've realized that Future.cancel() method can be used to stop the execution of the thread, but to my dismay its not working. Of course future.get() method is sending an interrupt to the Thread after the stipulated time (in my case its 2 seconds) and even the thread is receiving this interrupt but this interruption is taking place only once the thread is done with its execution completely. But I want to kill the thread after 2 seconds.

Could anyone help me how to achieve this.

Testclass code:

====================================

public class TestExecService {

      public static void main(String[] args) {

          //checkFixedThreadPool();
          checkCallablePool();

          }

      private static void checkCallablePool()
      {
          PrintCallableTask task1 = new PrintCallableTask("thread1");

          ExecutorService threadExecutor = Executors.newFixedThreadPool(1);
          Future<String> future = threadExecutor.submit(task1);

          try {
                System.out.println("Started..");
                System.out.println("Return VAL from thread ===>>>>>" + future.get(2, TimeUnit.SECONDS));
                System.out.println("Finished!");
            }
          catch (InterruptedException e) 
          {
            System.out.println("Thread got Interrupted Exception ==============================>>>>>>>>>>>>>>>>>>>>>>>>>");
            //e.printStackTrace();
          }
          catch (ExecutionException e) 
          {
            System.out.println("Thread got Execution Exception ==============================>>>>>>>>>>>>>>>>>>>>>>>>>");
          }
          catch (TimeoutException e)
          {
            System.out.println("Thread got TimedOut Exception ==============================>>>>>>>>>>>>>>>>>>>>>>>>>");
            future.cancel(true);
          }

          threadExecutor.shutdownNow();

      }
}

Callable Class code:

===================================================================
package com.test;

import java.util.concurrent.Callable;

public class PrintCallableTask implements Callable<String> {

      private int sleepTime;
      private String threadName;

    public PrintCallableTask(String name)
    {
        threadName = name;
        sleepTime = 100000;     
    }

    @Override
    public String call() throws Exception {

        try {
              System.out.printf("%s going to sleep for %d milliseconds.\n", threadName, sleepTime);
              int i = 0;

              while (i < 100000)
              {
                  System.out.println(i++);
              }


              Thread.sleep(sleepTime); // put thread to sleep
              System.out.printf("%s is in middle of execution \n", threadName);

            } catch (InterruptedException exception) {
              exception.printStackTrace();
            }


            System.out.printf("%s done sleeping\n", threadName);

            return "success";
    }

}
Malcolm answered 29/11, 2012 at 10:15 Comment(0)
G
10

Your code does everything right. The only problem is that you're not checking Thread.isInterrupted in the while loop. The only way for thread to get the message is to get to the blocking call Thread.sleep which will immediately throw InterruptedException. If loop is lengthy it can take some time. That's exactly why your code is a little bit unresponsive.

Check for interruption status, say, every 10,000 iterations:

while (i < 100000) {

    if (i % 10000 == 0 && Thread.currentThread().isInterrupted())
        return "fail";

    System.out.println(i++);
}

InterruptedException is for lengthy blocking methods. Thread.isInterrupted is for everything else.

Glenoid answered 29/11, 2012 at 23:17 Comment(1)
What if I have no control over the Runnable? (it is inside a third-party library?)Counterinsurgency
T
4

cancel() just calls interrupt() for already executing thread.

http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html:

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.

Interrupted thread would throw InterruptedException only

when a thread is waiting, sleeping, or otherwise paused for a long time and another thread interrupts it using the interrupt() method in class Thread.

So you need to explicitly make job code in executing thread aware of possible interruption.

See also Who is calling the Java Thread interrupt() method if I'm not?.

See also How to cancel Java 8 completable future? as java futures matured only by Java 8.

Taam answered 29/11, 2012 at 13:36 Comment(1)
Didn't you notice "for already executing"? It means already started task, as in question. See the source: grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…Taam

© 2022 - 2024 — McMap. All rights reserved.