I’ve got working spring MVC app and what I’m trying to do next is to start or submit a background task from my app.
Basically I’d like to keep the task going until it completes even if the user decides to do something else on the app.
But also I’d like to stop/kill/pause the task if I needed to. Since I haven’t done this before I’m looking for a good/better way to do this.
I found these to be useful:
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
How do you kill a thread in Java?
So I wanted to use @Async task to submit my background task, but wanted to use threads’ id to obtain it later on and stop it if needed?
Is this the right approach? I don’t have any experience with multithreading so I’m here to listen.
Code update :
public interface Worker {
public void work();
public void cancel();
}
implementation :
@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(); }
}
Controller for testing purposes :
@ResponseBody
@RequestMapping("/job/start")
public String start() {
asyncWorker.work();
return "start";
}
@ResponseBody
@RequestMapping("/job/stop")
public String stop() {
asyncWorker.cancel();
return "stop";
}
When I visit /job/start, I can’t execute more that one task simultaneously. The other one starts to execute only after first one has completed
Also when I visit /job/stop the process isn’t stopped, what am I missing here?
Using thread ID is too low level and brittle. If you decided to use
@Asyncannotation (good choice) you can useFuture<T>to control the task execution. Basically your method should return aFuture<T>instead ofvoid:Now you can
cancel()thatFutureor wait for it to complete:The tricky part is to store the returned
futureobject somehow so it is available for subsequent requests. Of course you cannot use a field orThreadLocal. You can put in session, note however thatFutureis not serializable and won’t work across clusters.Since
@Asyncis typically backed by thread pool, chances are your tasks didn’t even started. Cancelling will simply remove it from the pool. If the task is already running, you can theisInterrupted()thread flag or handleInterruptedExceptionto discovercancel()call.