2009-08-15 74 views
7

在下面的代码中,我按照预期在100秒后捕获了TimeoutException。在这一点上,我希望代码退出主要和程序终止,但它不断打印到控制台。如何让任务在超时后停止执行?如何在TimeoutException后返回FutureTask?

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 

private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { 
    FutureTask<T> task = new FutureTask<T>(c); 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 


public static void main(String[] args) { 

    try { 
     int returnCode = timedCall(new Callable<Integer>() { 
      public Integer call() throws Exception { 
       for (int i=0; i < 1000000; i++) { 
        System.out.println(new java.util.Date()); 
        Thread.sleep(1000); 
       } 
       return 0; 
      } 
     }, 100, TimeUnit.SECONDS); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     return; 
    } 


} 

回答

8

您需要取消超时你的任务(和中断它的线程)退出VM。这就是cancel(true)方法的用途。 :

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 

private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 


public static void main(String[] args) { 
     try { 
      FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() { 
       public Integer call() throws Exception { 
         for (int i=0; i < 1000000; i++) { 
           if (Thread.interrupted()) return 1; 
           System.out.println(new java.util.Date()); 
           Thread.sleep(1000); 
         } 
         return 0; 
       } 
      }); 
      int returnCode = timedCall(task, 100, TimeUnit.SECONDS); 
     } catch (Exception e) { 
       e.printStackTrace(); 
       task.cancel(true); 
     } 
     return; 
} 
+1

!task.cancelled()应该是!isCancelled()就像djna最初写的 – Zed 2009-08-15 06:24:01

+1

我认为使用中断要好得多。首先,你的可调用代码根本不需要知道“任务”。其次,当你在可调用代码中使用各种阻塞操作时(例如'Thread.sleep()'),这些操作不会对task.isCancelled()作出反应,但通常会对中断做出反应。所以使用'cancel(true)'并且让你的代码知道中断通常是最好的方法。 (你的代码也会更普遍,因为中断机制在Java中被广泛使用) – 2009-08-15 06:35:48

+0

我想我的观点是“中断是一种合作机制”。 (http://www.ibm.com/developerworks/java/library/j-jtp05236.html) – 2009-08-15 06:44:17

1

一旦你抓住了TimeoutException异常,你需要打电话给你任务的取消(true)方法...

或致电shutdownNow时()关闭您的ExecutorService ...

或者通过调用System.exit(0)

根据您的需要

4

您的Callable必须能够在需要时快速停止。

您的代码:

public Integer call() throws Exception { 
    for (int i=0; i < 1000000 && !task.cancelled(); i++) { 
     System.out.println(new java.util.Date()); 
     Thread.sleep(1000); // throws InterruptedException when thread is interrupted 
    } 
    return 0; 
} 

已经能够做到这一点得益于调用Thread.sleep()。要点是futureTask.cancel(true)会中断其他线程,并且你的代码需要对这个中断做出反应。 Thread.sleep()这样做。如果您没有使用Thread.sleep()或其他可中断的阻止代码,则必须自行检查Thread.currentThread().isInterrupted(),并在您发现这种情况时尽快退出(例如通过投掷new InterruptedException())。

您需要从异常处理程序调用futureTask.cancel(true);取消并中断运行您的任务的线程。

我的建议是了解中断机制(这是一篇很棒的文章:Dealing with InterruptedException),并使用它。