Reputation: 173
I want to implement the ExecutorService in my Spring-MVC application.
I need a global ExecutorService which take tasks put them in a queue and then executes them sequentially. So I want to pass the tasks from different locations in the application. Therefore I am using the Executors.newSingleThreadExecutor();
so I have only 1 thread executing these tasks.
However, I am not sure how to integrate it in a Spring application:
public enum TaskQueue {
INSTANCE;
ExecutorService executorService;
private TaskQueue() {
executorService = Executors.newSingleThreadExecutor();
}
public void addTaskToQueue (Runnable task){
executorService.submit(task);
executorService.shutdown();
}
}
So I am thinking of creating a Singleton and then just passing the Task (Runnable object) to the method:
TaskQueue.INSTANCE.addTaskToQueue(new Runnable() {
@Override
public void run() {
System.out.println("Executing Task1 inside : " + Thread.currentThread().getName());
}
});
However, I have several questions:
I am not sure how to integrate it in a Spring MVC application where I have controllers, services and so on.
The application receives some notifications from a web-service. These notifications will be processed on different locations in the code. I want to execute them sequentially. So I need to identify all tasks I want to run asynchronously and then pass them to the method above (`addTaskToQueue) wrapped in a Runnabel object, so they can be executed asynchronously. Is this the correct approach?
So I always pass a Runnable objects to this method to execute it. This method executes it and shuts the executorservice down. So each time I pass a task to this service - it creates a new service and then closes it. But I dont want to have that - I want the executorservice to stay alive and execute the tasks that are comming and not shutdown after each task. How do I achieve this?
Or am I totally wrong in implementing it this way?
EDIT:
Using the TaskExecutor provided by Spring - I would implement it like this:
@Autowired
private TaskExecutor taskExecutor;
Then calling it from different location in my code:
taskExecutor.execute(new Runnable() {
@Override
public void run() {
//TODO add long running task
}
});
Probably I need to make sure somewhere in the configuration that it needs to be executed sequentially - so it should create only 1 thread. Is it safe to call it from different locations? It wont always create a new service with a new queue?
Upvotes: 0
Views: 2483
Reputation: 2721
The Singleton design pattern is not a very good fit for this. Since you're using Spring, it makes much more sense to make a component with @PostConstruct
and @PreDestroy
methods. Here and here are articles that explain this.
In your case, I'd do something like the following:
@Component
public class TaskQueue {
private ExecutorService executorService;
@PostConstruct
public void init() {
executorService = Executors.newSingleThreadExecutor();
}
@PreDestroy
public void cleanup() {
executorService.shutdown();
}
public void addTaskToQueue (Runnable task){
executorService.submit(task);
}
}
And then you can autowire this component.
Edit: @Ivan's answer is to be preferred.
Upvotes: 0
Reputation: 8758
Spring already has a bean for this: org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
. It implements DisposableBean
interface and shutdown()
method is called when Spring context is destroyed.
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="${threadPoolSize}"/>
<property name="maxPoolSize" value="${threadPoolSize}"/>
<property name="WaitForTasksToCompleteOnShutdown" value="false"/>
</bean>
Upvotes: 3