ManagedExecutorService for Implementing Concurrency Utilities in Java EE 7 – Part 1

SHARE & COMMENT :

Prior to Java EE 7 one could make use of the concurrency utilities present in java.util.concurrent package or the java.lang.Thread or java.lang.Runnable. But it was not considered a best practice, not a standard and not safe for the application. This was because the Java EE web and EJB containers instantiate objects using container-managed thread pools and creating a new (non-managed) Thread object, the container could not guarantee that other Java EE platform services (for example, transactions and security) would be part of this Thread.

Due to this major drawback independent, unmanaged threads were not created in a Java EE application. With Java EE 7 a new API has been added to make the features of java.util.concurrent package available to the Java EE application in a safe and standard way. In this post I am going to look at one such API called ManagedExecutorService. This is a managed version of ExecutorService API present in java.util.concurrent package.

What is a ManagedExecutorService?

From the JavaDocs:

A ManagedExecutorService extends the Java™ SE ExecutorService to provide methods for submitting tasks for execution in a Java™ EE environment. Implementations of the ManagedExecutorService are provided by a Java™ EE Product Provider. Application Component Providers use the Java Naming and Directory Interface™ (JNDI) to look-up instances of one or more ManagedExecutorService objects using resource environment references. ManagedExecutorService instances can also be injected into application components through the use of the Resource annotation.

Following are the important observations from the description above:

  1. Extends the Java SE ExecutorService
  2. Provides methods for submitting tasks for execution in a Java EE environment
  3. Implementations are provided by a Java EE producy provider
  4. Use JNDI to look-up instances of one ore more ManagedExecutorService objects
  5. ManagedExecutorService can also be injected into the application components through the use of the resource annotation

In the Point-2 above the tasks are written by either implementing the java.util.concurrent.Callable or the java.lang.Runnable interfaces. The difference between java.util.concurrent.Callable and java.lang.Runnable are:

  1. Callable contains a call() method which returns a value where as Runnable contains run() method which doesnt return any value.
  2. Callable can throw checked exceptions where as Runnable cannot.

Using the ManagedExecutorService

I am going to divide this section into 4 parts namely:

  1. Obtaining instance of default ManagedExecutorService using JNDI lookup
  2. Submitting tasks using the submit() method.
  3. Submitting tasks using the invokeAll() method.
  4. Submitting tasks using the invokeAny() method.

Obtaining instance of default ManagedExecutorService

As mentioned before the default instance of ManagedExecutorService can be obtained by using a JNDI lookup. This lookup can be done by executing the method or via the annotation. The JDNI lookup for default is: java:comp/DefaultManagedExecutorService. One can provide their own JNDI lookups which has to be configured in the web.xml. Lets look at the below code which obtains the default ManagedExecutorService instance using both the approaches:

//Using method invocation
//Create a InitContext instance
InitialContext context = new InitialContext();

//Obtaining a default ManagedExecutorService
//Using the java:comp/DefaultManagedExecutorService
ManagedExecutorService executorService =
      (ManagedExecutorService) context.lookup("java:comp/DefaultManagedExecutorService");

//Using annotation
@Resource(lookup="java:comp/DefaultManagedExecutorService")
ManagedExecutorService executor;

In the rest of the post I will be using the method invocation approach.

Submitting tasks using the submit() method

Lets look at an example code which submits both Callable tasks and Runnable tasks:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException, NamingException, InterruptedException, ExecutionException {
  response.setContentType("text/html;charset=UTF-8");
  final PrintWriter out = response.getWriter();
  try {
    out.println("<!DOCTYPE html>");
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Servlet ConcurrencyDemo</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Servlet ConcurrencyDemo at " + request.getContextPath() + "</h1>");
    out.println("</body>");
    out.println("</html>");

    //Create a InitContext instance
    InitialContext context = new InitialContext();

    //Obtaining a default ManagedExecutorService
    //Using the java:comp/DefaultManagedExecutorService
    ManagedExecutorService executorService =
            (ManagedExecutorService) context.lookup("java:comp/DefaultManagedExecutorService");

    out.println("MethodExecutorService#submit(Callable)<br/>");
    //Using the submit method to submit a Callable task.
    Future<String> result = executorService.submit(new Callable<String>() {
      @Override
      public String call() throws Exception {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 10; i++) {
          builder.append("String number ").append(i).append("<br/>");
        }

        return builder.toString();
      }
    });

    //retrieving the result from the callable task completion.
    out.println("Output from the Callable invoked using <code>submit()</code>: <br/>" + result.get());

    //Using the submit method to submit a Runnable task which doesn't have any return value.
    out.println("ManagedExecutorService#submit(Runnable)<br/>");
    executorService.submit(new Runnable() {
      @Override
      public void run() {
        for (int i = 0; i < 10; i++) {
          out.println("String number " + i+"<br/>");
        }
      }
    });

  } finally {
    out.close();
  }
}

The above processRequest() method can be invoked from the doGet() and doPost() methods of the servlet which you have crated. And executing the above code on a servlet gives the following output:
Managed_Exec_Service_2

Submitting tasks using invokeAll() method

The invokeAll() method is used to invoke multiple Callback tasks at the same time. A list of Callback tasks is created and is passed as a parameter to the invokeAll() method. Lets look at the code below:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException, NamingException, InterruptedException, ExecutionException {
  response.setContentType("text/html;charset=UTF-8");
  final PrintWriter out = response.getWriter();
  try {
    /* TODO output your page here. You may use following sample code. */
    out.println("<!DOCTYPE html>");
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Servlet ConcurrencyDemo</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Servlet ConcurrencyDemo at " + request.getContextPath() + "</h1>");
    out.println("</body>");
    out.println("</html>");

    //Create a InitContext instance
    InitialContext context = new InitialContext();

    //Obtaining a default ManagedExecutorService
    //Using the java:comp/DefaultManagedExecutorService
    ManagedExecutorService executorService =
            (ManagedExecutorService) context.lookup("java:comp/DefaultManagedExecutorService");

    /**
     * Using the invokeAll method
     */
    out.println("MethodExecutorService#invokeAll(Callable)<br/>");
    List<Callable<String>> callableList = new ArrayList<>();
    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        return "Done processing Callable Task 1";
      }
    });

    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Thread.sleep(10000);
        return "Done processing Callable Task 2";
      }
    });

    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Thread.sleep(1000);
        return "Done processing Callable Task 3";
      }
    });

    out.println("Output from the Callables invoked using <code>invokeAll()</code>: <br/>");
    List<Future<String>> futuresList = executorService.invokeAll(callableList);
    for(Future<String> future: futuresList){
      out.println(future.get()+"<br/>");
    }

  } finally {
    out.close();
  }
}

The above method can be invoked from any servlet and the resulting output is:
Managed_Exec_Service_3

Submitting tasks using invokeAny() method

The invokeAny() method accepts a list of Callable tasks just like the invokeAll() method. The difference is that once the invokeAny() method receives result from any one of the tasks, then it suspends the rest of the tasks. Lets look at the code below:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException, NamingException, InterruptedException, ExecutionException {
  response.setContentType("text/html;charset=UTF-8");
  final PrintWriter out = response.getWriter();
  try {
    /* TODO output your page here. You may use following sample code. */
    out.println("<!DOCTYPE html>");
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Servlet ConcurrencyDemo</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Servlet ConcurrencyDemo at " + request.getContextPath() + "</h1>");
    out.println("</body>");
    out.println("</html>");

    //Create a InitContext instance
    InitialContext context = new InitialContext();

    //Obtaining a default ManagedExecutorService
    //Using the java:comp/DefaultManagedExecutorService
    ManagedExecutorService executorService =
            (ManagedExecutorService) context.lookup("java:comp/DefaultManagedExecutorService");

    List<Callable<String>> callableList = new ArrayList<>();
    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        return "Done processing Callable Task 1";
      }
    });

    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Thread.sleep(10000);
        return "Done processing Callable Task 2";
      }
    });

    callableList.add(new Callable<String>() {

      @Override
      public String call() throws Exception {
        Thread.sleep(1000);
        return "Done processing Callable Task 3";
      }
    });

    out.println("MethodExecutorService#invokeAny(Callable)<br/>");
    out.println("Output from the Callables invoked using <code>invokeAll()</code>: <br/>");
    String invokeAnyResult = executorService.invokeAny(callableList);
    out.println(invokeAnyResult+"<br/>");

  } finally {
    out.close();
  }
}

Managed_Exec_Service_4
In the above screenshot you can see that only one result if obtained though 3 tasks were submitting for execution. The other two tasks had sleep() method invoked which delayed their completion.

With this I have covered the different ways of submitting tasks for execution using the ManagedExecutorService interface. If you want to run and try out the above code, please include the processRequest() method into your servlet class and invoke the processRequest() from doGet() or doPost() methods.

Note: Dont try to work out all the above examples i.e submit(), invokeAll() and invokeAny() together as it will not give right printing order due to the difference in Thread scheduling. Hence I have discussed them separately.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better