2012-10-01 34 views
10

我已经有工作的春天MVC应用程序,接下来我要做的是从我的应用程序启动或提交后台任务。从春天mvc应用程序提交背景任务

基本上我想保留任务直到它完成,即使用户决定在应用程序上做其他事情。

但是如果我需要,我也想停止/终止/暂停任务。因为在我寻找更好/更好的方式来做到这一点之前,我还没有做到这一点。

我认为这是一个非常有用:

http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/

How do you kill a thread in Java?

Java threads: Is it possible view/pause/kill a particular thread from a different java program running on the same JVM?

所以我想用@Async任务提交我的后台任务,但希望使用线程id稍后获取并在需要时停止它?

这是正确的做法吗?我没有多线程的经验,所以我在这里倾听。

代码更新:

public interface Worker { 
    public void work(); 
    public void cancel(); 
} 

实现:

@Component("asyncWorker") 
public class AsyncWorker implements Worker { 

    @Async 
    public void work() { 
     String threadName = Thread.currentThread().getName(); 
     System.out.println(" " + threadName + " beginning work"); 
     try { 
       Thread.sleep(10000); // simulates work 
     } catch (InterruptedException e) { 
      System.out.println("I stopped"); 
     } 
     System.out.println(" " + threadName + " completed work"); 
    } 

    public void cancel() { Thread.currentThread().interrupt(); } 
} 

控制器,用于测试目的:

@ResponseBody 
@RequestMapping("/job/start") 
public String start() { 
    asyncWorker.work(); 
    return "start"; 
} 

@ResponseBody 
@RequestMapping("/job/stop") 
public String stop() { 
    asyncWorker.cancel(); 
    return "stop"; 
} 

当我访问/job/start,我无法执行一个以上的任务同时。另一个只在第一个完成后才开始执行

另外,当我访问/job/stop过程不停止,我在这里失踪了什么?

回答

9

使用线程ID太低且易碎。如果您决定使用@Async annotation(不错的选择),则可以使用Future<T>来控制任务执行。基本上,你的方法应该返回的Future<T>代替void

@Async 
public Future<Work> work() //... 

现在你可以cancel()Future或等待其完成:

@ResponseBody 
@RequestMapping("/job/start") 
public String start() { 
    Future<Work> future = asyncWorker.work(); 
    //store future somewhere 
    return "start"; 
} 

@ResponseBody 
@RequestMapping("/job/stop") 
public String stop() { 
    future.cancel(); 
    return "stop"; 
} 

棘手的部分是以某种方式存储返回future对象,它可用于随后的请求。当然,你不能使用字段或ThreadLocal。您可以放入会话中,但请注意Future不可序列化,并且不会跨群集工作。

由于@Async通常由线程池支持,因此您的任务很可能还没有开始。取消只会将其从游泳池中移除。如果任务已经运行,则可以通过线程标记isInterrupted()或处理InterruptedException来发现cancel()调用。

+0

+1 for @Async。你可以添加一个链接到http:// static。springsource.org/spring/docs/3.0.x/reference/scheduling.html? –

+0

@Tomasz Nurkiewicz你好,谢谢你的回复。实际包含'fooAsync()'实现的类是否需要实现Runnable?如果我创建了一个中断线程执行后台任务的取消方法,Thread.currentThread()中断会中断那个特定的线程吗?你能举个例子吗? –

+0

@DavidGrant:当然,您也可以自由编辑SO上的任何帖子(您已经这么做了,谢谢)。 –