Метод Future.cancel () не работает

Код, который у меня есть, создает экземпляр Callable, и с помощью ExecutorService создается новый поток. Я хочу убить этот поток через определенное время, если поток не завершил свое выполнение. Пройдя через документацию jdk, я понял, что метод Future.cancel () можно использовать для остановки выполнения потока, но, к моему разочарованию, он не работает. Конечно, метод future.get () отправляет прерывание в поток по истечении установленного времени (в моем случае это 2 секунды), и даже поток получает это прерывание, но это прерывание происходит только после того, как поток завершил свое выполнение полностью. Но я хочу убить поток через 2 секунды.

Может ли кто-нибудь помочь мне в этом.

Код тестового класса:

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

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();

      }
}

Код вызываемого класса:

===================================================================
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";
    }

}

person Ismail Shaik    schedule 29.11.2012    source источник


Ответы (2)


Ваш код все делает правильно. Единственная проблема в том, что вы не проверяете Thread.isInterrupted в цикле while. Единственный способ для потока получить сообщение - это перейти к блокирующему вызову Thread.sleep, который немедленно вызовет InterruptedException. Если цикл длинный, это может занять некоторое время. Именно поэтому ваш код немного не отвечает.

Проверяйте статус прерывания, скажем, каждые 10 000 итераций:

while (i < 100000) {

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

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

InterruptedException предназначен для длительных методов блокировки. Thread.isInterrupted для всего остального.

person Community    schedule 29.11.2012
comment
Что делать, если у меня нет контроля над Runnable? (это внутри сторонней библиотеки?) - person pihentagy; 20.01.2015

cancel() просто вызывает interrupt() для уже выполняющегося потока.

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

Прерывание - это указание потоку, что он должен остановить то, что он делает, и сделать что-то еще. Программист должен решить, как именно поток реагирует на прерывание, но очень часто поток завершается.

Прерванный поток вызовет только InterruptedException

когда поток ожидает, спит или иным образом приостановлен на долгое время, а другой поток прерывает его, используя метод interrupt () в классе Thread.

Таким образом, вам необходимо явно указать в коде задания при выполнении потока информацию о возможном прерывании.

См. Также Кто вызывает прерывание потока Java ( ), если нет?.

См. Также Как отменить завершаемое будущее Java 8? по мере созревания будущего java только на Java 8.

person Vadzim    schedule 29.11.2012
comment
Разве вы не заметили, что уже выполняются? Это означает, что уже запущенная задача, как рассматриваемая. См. Источник: grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/ - person Vadzim; 30.11.2012