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

Java 计时器:取消正在运行的任务,java,timer,tomcat7,scheduled-tasks,Java,Timer,Tomcat7,Scheduled Tasks,我需要创建一个异步线程,该线程运行一次,延迟2分钟,并且可以随时终止。我看到了几种可能的解决方案: ScheduledExecutorService和FutureTask允许我中断正在运行的任务,但我必须调用shutdown()来终止所有正在运行的线程,这将阻止用户,直到进程终止。此外,我还必须经常调用Thread.interrupted(),如中所述 Timer和TimerTask不需要释放正在运行的线程,但我无法中断正在运行的计时器线程(Timer.cancel()只是取消未来的调度) 有问

我需要创建一个异步线程,该线程运行一次,延迟2分钟,并且可以随时终止。我看到了几种可能的解决方案:

  • ScheduledExecutorService
    FutureTask
    允许我中断正在运行的任务,但我必须调用
    shutdown()
    来终止所有正在运行的线程,这将阻止用户,直到进程终止。此外,我还必须经常调用
    Thread.interrupted()
    ,如中所述
  • Timer
    TimerTask
    不需要释放正在运行的线程,但我无法中断正在运行的计时器线程(
    Timer.cancel()
    只是取消未来的调度)
  • 有问题地使用 有好的解决办法吗?(我正在使用tomcat 7)


    感谢您使用选项1,您可以将
    可能中断fRunning
    参数设置为
    true
    以取消任务

    创建一个,仍然可以通过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");
    }
    
    publicstaticvoidmain(String[]args)抛出InterruptedException{
    ScheduledThreadPoolExecutor executor=新的ScheduledThreadPoolExecutor(2);
    ScheduledFuture future=executor.scheduleAtFixedRate(new Runnable()){
    int i=0;
    公开募捐{
    int j=i++;
    系统错误println(“运行”+j);
    试一试{
    线程。睡眠(5000L);
    }捕捉(中断异常e){
    系统错误println(“中断”+j);
    }
    }
    },1000L,2000L,时间单位为毫秒);
    线程。睡眠(10000L);
    System.err.println(“已取消”+future.cancel(true));
    线程。睡眠(20000L);
    执行者。关机现在();
    系统错误打印项次(“完成”);
    }
    
    经过一些测试和研究,FutureTask.cancel()和线程需要类似的中断处理,如中所述

  • 检查逻辑中的中断标志
  • 根据中断的例外情况采取行动
  • 测试中断标志的示例:

    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 
                ...
            }
        }
    }
    
    private final类MyTask实现可运行{
    公开募捐{
    试一试{
    
    对于(int j=0;j对于使用TimerTask的场景2,为什么不在调用this.cancel()之后从run()方法返回呢

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

    ...
    if ( count < 1 ) {
       logger.error("CANCELING THREAD FOR " + host + ":" + jmxPort + "! " +
                    "- CONFIGURATION INCOMPLETE - DUMP_COUNT must be 1 or greater.");
       this.cancel();
       return;
    }
    ...
    
    。。。
    如果(计数<1){
    logger.error(“取消“+host+”的线程:“+jxport+”!”+
    “-配置不完整-转储_计数必须为1或更大。”);
    这个。取消();
    返回;
    }
    ...
    
    没错,但有两个缺点。首先,如果我在线程中启动一个长进程,我必须不断地引用isInterrupted标志;其次,我必须调用shutdown来释放正在运行的线程,这将阻止用户,直到线程完成运行。ExecutorService返回的FutureTask会使您无法使用线程。根据JavaDoc,如果您为MayInterruptFrunning传递true,它将负责中断工作线程。这与Enno Shioji的回答不完全一致:我使用ScheduledFuture javaDoc的附加引用更新了我的答案,该引用明确表示可以取消计划任务。谢谢,我将对其进行测试。但这种方法仍然需要我调用ScheduledFuturedExecutorService.shutdown()最终释放线程。我不想阻止用户并等待所有线程完成运行