定时器:取消正在运行的任务

问题描述:

我需要创建异步线程,运行一次,延迟时间为2分钟,可以在任何时刻终止。我看见几个可能的解决方案:定时器:取消正在运行的任务

  1. ScheduledExecutorServiceFutureTask让我中断正在运行的任务,但我将不得不调用shutdown()终止所有正在运行的线程,这将阻止用户直到进程被终止。此外,我将不得不经常调用Thread.interrupted(),如Enno Shioji's answer中所述。
  2. TimerTimerTask不需要释放运行的线程,但我没有办法打断一个正在运行的计时器线程(Timer.cancel()刚刚取消的未来计划)
  3. 使用Thread and sleepthread interruption问题。

有没有很好的解决方案? (我使用Tomcat 7)

谢谢

一些试验和研究后,FutureTask.cancel()和线程需要中断的类似处理,如Enno Shioji's answer

  1. 检查中断标志在你的逻辑
  2. 法追访时表示例外

例子tes TS中断标志:

private final class MyTask implements Runnable { 

    public void run() { 
     try{ 
      for(int j=0; j<100000000; j++) { 
       for(int i=1; i<1000000000; i++){ 
        if(Thread.interrupted()){ //Don't use Thread.interrupt()! 
         Log.debug("Thread was interrupted for" + cache); 
         return; //Stop doing what you are doing and terminate. 
        } 
        Math.asin(0.1565365897770/i); 
        Math.tan(0.4567894289/i); 
       } 
      }        
     }catch(Throwable e){//if exception is uncaught, the scheduler may not run again 
      ... 
     } 
    } 
} 

据我了解,ScheduledExecutorService也许是shutdown当应用程序结束运行

使用选项1,您可以使用FutureTask.cancel()mayInterruptIfRunning参数设置为true取消任务。

ScheduledExecutorService.scheduleAtFixedRate()创建一个ScheduledFuture,仍然可以通过FutureTask api取消。

这是我用来验证任务被取消的天真测试。如果你做了一些阻塞IO(网络或磁盘),我想工作者线程可能不会被打断,但我还没有测试过。如果在任务没有运行的时候调用cancel函数,这一切都会很好地停止,但是如果在调用cancel函数时任务正在运行,执行程序将尝试终止线程。

public static void main(String[] args) throws InterruptedException { 
    ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2); 

    ScheduledFuture<?> future = executor.scheduleAtFixedRate(new Runnable() { 
     int i = 0; 
     public void run() { 
      int j = i++; 
      System.err.println("Run " + j); 

      try { 
       Thread.sleep(5000L); 
      } catch (InterruptedException e) { 
       System.err.println("Interrupted " + j); 
      } 
     } 

    }, 1000L, 2000L, TimeUnit.MILLISECONDS); 

    Thread.sleep(10000L); 
    System.err.println("Canceled " + future.cancel(true)); 

    Thread.sleep(20000L); 

    executor.shutdownNow(); 
    System.err.println("Finished"); 
} 
+0

没错,但有两个缺点。首先,如果我在线程中启动一个长进程,我必须不断地引用isInterrupted标志;第二,我必须调用shutdown来释放正在运行的线程,这将阻塞用户,直到线程运行完毕 – lili 2012-03-28 19:27:09

+0

ExecutorService返回的FutureTask将您抽象为使用线程。按照JavaDoc,如果您为mayInterruptIfRunning传递true,它将负责中断工作线程。 – 2012-03-28 19:34:45

+0

不完全是根据恩诺盐路的回答是:http://*.com/questions/2903342/why-thread-started-by-scheduledexecutorservice-schedule-never-quits – lili 2012-03-28 19:36:09

您的方案2的TimerTask,为什么不从run()方法返回调用this.cancel后( )?

这是我写的东西的片段。每当工具遇到会导致进一步执行无效的情况时(例如错误配置),我都会使用相同的技术。

... 
if (count < 1) { 
    logger.error("CANCELING THREAD FOR " + host + ":" + jmxPort + "! " + 
       "- CONFIGURATION INCOMPLETE - DUMP_COUNT must be 1 or greater."); 
    this.cancel(); 
    return; 
} 
...