How to concurrently execute tasks using Java in Spring

This tutorials will show you how we can concurrently execute different operations using Java utility class called java.util.concurrent.Executors in Spring framework.

Spring supports XML as well as Programmatic configuration of beans but, here we will use XML based metadata configuration.

If you already have an idea on how to create a maven project in Eclipse will be great otherwise I will tell you here how to create a maven project in Eclipse.

Prerequisites
The following things are required in order to run the application
Eclipse Kepler
JDK 1.8
Have maven 3 installed and configured
Spring dependencies in pom.xml
Now we will see the below steps how to create a maven based spring project in Eclipse
Step 1. Create a standalone maven project in Eclipse

Go to File -> New -> Other. On popup window under Maven select Maven Project. Then click on Next. Select the workspace location – either default or browse the location. Click on Next. Now in next window select the row as highlighted from the below list of archtypes and click on Next button.

maven-arctype-quickstart
Now enter the required fields (Group Id, Artifact Id) as shown below
Group Id : com.roytuts
Artifact Id : spring-hsqldb
Step 2. Modify the pom.xml file as shown below.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.roytuts</groupId>
    <artifactId>spring-method-injection</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>spring-method-injection</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.8</jdk.version>
        <junit.version>4.11</junit.version>
        <spring.version>4.1.5.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Step 3. If you see JRE System Library[J2SE-1.4] then change the version by below process

Do right-click on the project and go to Build -> Configure build path, under Libraries tab click on JRE System Library[J2SE-1.4], click on Edit button and select the appropriate jdk 1.8 from the next window. Click on Finish then Ok.

Step 4. Create src/main/resources folder for putting the resource files.

Do right-click on the project and go New -> Source Folder. Give Folder name: as src/main/resources and click on Finish button.

Step 5. Create an XML configuration file under src/main/resources.

Do right-click on src/main/resources in the project and go New -> file. Give File name: as applicationContext.xml and click on Finish button.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- use annotation based property in classes -->
    <context:annotation-config />
    <!-- we are creating 10 threads -->
    <bean id="executorService" class="java.util.concurrent.Executors"
        factory-method="newFixedThreadPool" destroy-method="shutdown">
        <constructor-arg value="10" />
    </bean>
    <!-- singleton class -->
    <bean id="taskExecutor" class="com.roytuts.task.executor.TaskExecutor"
        factory-method="getInstance">
        <property name="executorService" ref="executorService" />
    </bean>
    <!-- returns different tasks -->
    <bean id="taskFactory" class="com.roytuts.task.factory.AbstractTaskFactory"
        scope="singleton">
        <lookup-method name="createPrototype" bean="messageTask" />
    </bean>
    <bean id="messageTask" class="com.roytuts.task.GreetingMessageTask"
        scope="prototype">
    </bean>
    <!-- providing service -->
    <bean id="greetingMessageService" class="com.roytuts.service.impl.GreetingMessageServiceImpl"
        scope="singleton">
        <property name="taskFactory" ref="taskFactory" />
        <property name="taskExecutor" ref="taskExecutor" />
    </bean>
</beans>

Step 6. Create a class called TaskExecutor that returns a single instance and submit the task.

package com.roytuts.task.executor;
import java.util.concurrent.ExecutorService;
import com.roytuts.task.Task;
public class TaskExecutor {
  private static TaskExecutor instance;
  private ExecutorService executorService;
  private TaskExecutor() {}
  public static TaskExecutor getInstance() {
    if (null == instance) {
      synchronized (TaskExecutor.class) {
        if (null == instance) {
          instance = new TaskExecutor();
        }
      }
    }
    return instance;
  }
  public ExecutorService getExecutorService() {
    return executorService;
  }
  public void setExecutorService(ExecutorService executorService) {
    this.executorService = executorService;
  }
  public void submitTask(Task task) {
    executorService.execute(task);
  }
}

Step 7. Create an interface called Task with the following source code

package com.roytuts.task;
import java.util.Map;
public interface Task extends Runnable {
  void setParams(Map<String, Object> mapParams);
}

The class which is going to implement the above interface is a Task of that type and if that class needs to set any parameters for executing its operation then it is going to set using setparams() method.

Step 8. Create an AbstractTask that will execute the operations needed for a specific Task

package com.roytuts.task;
import java.util.Map;
public abstract class AbstractTask implements Task {
  protected Map<String, Object> mapParams;
  @Override
  public void run() {
    execute();
  }
  @Override
  public void setParams(Map<String, Object> mapParams) {
    this.mapParams = mapParams;
  }
  protected abstract void execute();
}

Step 9. Create a Java class called AbstractTaskFactory that will return different tasks.

package com.roytuts.task.factory;
import com.roytuts.task.Task;
public abstract class AbstractTaskFactory implements TaskFactory {
  protected abstract Task createPrototype();
  @Override
  public Task createTask() {
    return createPrototype();
  }
}

Step 10. Now we are going to create a class that will display greeting message when we submit the task. We can have also many other tasks submitted concurrently and will be executed concurrently.

package com.roytuts.task;
public class GreetingMessageTask extends AbstractTask {
  @Override
  protected void execute() {
    String message = (String) mapParams.get("message");
    System.out.println("Got message from submitted task : " + message);
  }
}

Step 11. We are going to create a service called GreetingMessageService.

package com.roytuts.service;
public interface GreetingMessageService {
  public void displayMessage(String message);
}

Step 12. This is an implementation of the above interface.

package com.roytuts.service.impl;
import java.util.HashMap;
import java.util.Map;
import com.roytuts.service.GreetingMessageService;
import com.roytuts.task.Task;
import com.roytuts.task.executor.TaskExecutor;
import com.roytuts.task.factory.TaskFactory;
public class GreetingMessageServiceImpl implements GreetingMessageService {
  private TaskFactory taskFactory;
  private TaskExecutor taskExecutor;
  public TaskFactory getTaskFactory() {
    return taskFactory;
  }
  public void setTaskFactory(TaskFactory taskFactory) {
    this.taskFactory = taskFactory;
  }
  public TaskExecutor getTaskExecutor() {
    return taskExecutor;
  }
  public void setTaskExecutor(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }
  @Override
  public void displayMessage(String message) {
    Map<String, Object> mapParams = new HashMap<String, Object>();
    mapParams.put("message", message);
    Task messageTask = taskFactory.createTask();
    messageTask.setParams(mapParams);
    taskExecutor.submitTask(messageTask);
    System.out.println("Task successfully submitted");
  }
}

Step 13. Create a Junit test case

package com.roytuts.task;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.roytuts.service.GreetingMessageService;
public class GreetingMessageTaskTest {
  GreetingMessageService greetingMessageService;
  @Before
  public void setUp() throws Exception {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    greetingMessageService = context.getBean("greetingMessageService", GreetingMessageService.class);
  }
  @Test
  public void testDisplayMessage() {
    greetingMessageService.displayMessage("Welcome to Task Executor Tutorial.");
  }
}

Step 14. Run the above test class you will get the following output in the console.

Task successfully submitted
Got message from submitted task : Welcome to Task Executor Tutorial.

That’s all. Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *