Skip to main content

Asynchronous Servlet and Java EE Concurrency Utilities

Posted by swchan2 on June 6, 2013 at 1:42 PM PDT

Asynchronous operation was introduced in Servlet 3.0. ServletRequest#startAsync is used to put the request into asynchronous mode. A thread need to be created implicitly or explicitly (see here for an example).

Servlet 3.1, JSR 340 includes clarifications in asynchronous area. Besides Servlet 3,1, Concurreny Utilities for Java EE 1.0, JSR 236 is introduced in Java EE 7. JSR 236 provides a portable way to access managed thread pools and ExecutorService in a Java EE container. In this blog, I will illustrate how to achieve this in a servlet asynchronous environment.

javax.enterprise.concurrent.ManagedThreadFactory#newThread

A ManagedThreadFactory can be accessed through JNDI resource lookup, which can be achieved through the @Resource annotation. A thread can be created from the factory as usual.

@WebServlet(urlPatterns="/test", asyncSupported=true)
public class TestAsyncMTFServlet extends HttpServlet {
    @Resource
    private ManagedThreadFactory managedThreadFactory;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        final AsyncContext asyncContext = req.startAsync();
        final PrintWriter writer = res.getWriter();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                writer.println("Done");
                asyncContext.complete();
            }
        };

        Thread thread = managedThreadFactory.newThread(runnable);
        thread.start();
    }
}

javax.enterprise.concurrent.ManagedExecutorService#submit, javax.enterprise.concurrent.ManagedScheduledExecutorService#schedule

Instead of accessing thread factory directly, ManagedExecutorService and ManagedScheduledExecutorService are also available through JNDI resource lookup. The following example illustrates the usage of the former.

@WebServlet(urlPatterns="/test2", asyncSupported=true)
public class TestAsyncMESServlet extends HttpServlet {
    @Resource
    private ManagedExecutorService managedExecutorService;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        final AsyncContext asyncContext = req.startAsync();
        final PrintWriter writer = res.getWriter();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                writer.println("Done");
                asyncContext.complete();
            }
        };

        managedExecutorService.submit(runnable);
    }
}

Servlet 3.1 and Concurrency Utilities for Java EE 1.0 are available in GlassFish 4.0.

Comments

I know this is just an example, but as given the request ...

I know this is just an example, but as given the request processing is just transferred from the http thread pool to the system thread pool. I would think there are more advantages in async http processing if the work for a request can be divided up in smaller tasks perhaps?

I like the ease with which we can inject the executor service, but such a shame it uses the old @Resource and not the newer @Inject, and that we're stuck with the thread pool the AS provides. This can only really be useful if applications can define their own pools. This is needed for QoS, to prevent deadlocks, starvation etc. One global pool just doesn't cut it.

We define another pool if you want. In GlassFish, you can do ...

We define another pool if you want. In GlassFish, you can do this through Admin console > Resources > Concurrent Resources. You can look up with the new resource with a new JNDI name.

Sorry, but going through GlassFish Admin console is not a ...

Sorry, but going through GlassFish Admin console is not a viable option for me, unless I can do this programmatically from code from within my war.

The pools belong to the application, I don't want (and typically can't) let the AS have application specific knowledge. This is also really difficult when developing. If I add a pool, remove a pool, tweak a pool etc, I check this change into version control. Then CI deploys a war to the AS. How do the changes I make in code end up as clicks in a GlassFish UI? How do I even know the AS is GlassFish? Maybe it's JBoss?

We don't give our JRE knowledge of the apps that are run on it, why do we need to do this for the AS when it comes to these thread pools?

You can get a ManagedThreadFactory and then construct a ...

You can get a ManagedThreadFactory and then construct a custom Executor.

If you want any additional API or functionality requirement, then you can send emails users@concurrency-ee-spec.java.net or file a jira issue to https://java.net/projects/concurrency-ee-spec . So that they can take a look at that in the next release.