Enterprise Java

Java EE: Asynchronous constructs and capabilities

asynchronous

Introduction

Java EE has a number of APIs and constructs to support Asynchronous execution. This is vital from a scalability and performance stand point.

Let us assume 2 modules which are interacting with each other. When moduleA (the sender) sends a message to moduleB (the receiver) in a Synchronous fashion, the communication takes place in the context of a Single thread i.e. the thread which initiated the communication from moduleA is blocked until moduleB responds back.

This was a generic statement but can be extended to the context of a simple Java methods interacting with each other – in this case, a synchronous call from methodA to methodB would execute in the same thread which would be blocked until methodB returns or throws an exception.

Why do we need Asynchronous behavior in Java EE based applications?

We can further extrapolate this point to the Java EE world – be it inter server communication e.g. between web tier and EJB tier (servlets and EJBs) or a typical client server interaction – a browser interacting with a RESTful end point, Servlets etc – the server thread which responds to a client request always blocks until the server component responds back.

Here is where Asynchronous execution comes into play – if the server thread processing the client request can be released/suspended and the actual business logic is executed in a separate thread (different than that of the original one), performance and scalability can be improved immensely ! E.g. if a HTTP listener thread allocated to listen to client requests is released immediately, then it is free to attend to requests from other clients and the business logic can be executed in a separate container thread which can then return the response via appropriate methods such as java.util.concurrent.Future object or via call back handlers registered by the client. Think from an end user perspective – responsiveness matters a lot!

Dive In: Async constructs and APIs in Java EE

Let’s take a look at few of the Async related features (APIs) in Java EE. This is not an exhaustive list – but should be a good starting point.

Different Java EE specs have their typical ways and APIs to facilitate Async capabilities. Let’s explore the below Java EE specifications

  • JAX-RS 2.0 (Java EE 7)
  • Websocket 1.0 (Java EE 7)
  • Concurrency Utilities 1.0 (Java EE 7)
  • EJB 3.1 (Java EE 6)
  • Servlet 3.0 (Java EE 6)

Note: The code presented below is in a snippet form (for obvious reasons). The complete samples can be accessed here

JAX-RS 2.0

Async processing of requests is a new feature in 2.0 edition of JAX-RS (new in Java EE 7). In order to execute an aysnc request using JAX-RS APIs, one needs to inject a reference to a javax.ws.rs.container.AsyncResponse interface in the JAX-RS resource method itself. This parameter puts the request execution in async mode and the method proceeds with its execution. The resume method on the AsynResponse object needs to be called from within a separate thread after the business logic execution is complete. One can leverage the Java EE concurrency utility features (discussed later) such as the javax.enterprise.concurrent.ManagedExecutorService in order to encapsulate the business logic as a Runnable object and submitting it to the container’s executor service which takes care of the rest. No need to spawn un-managed, isolated threads on your own.

@Path("/{id}")
    @GET
    @Produces("application/xml")
    public void asyncMethod(@Suspended AsyncResponse resp, @PathParam("id") String input) {

        System.out.println("Entered MyAsyncRESTResource/asyncMethod() executing in thread: "+ Thread.currentThread().getName());
        mes.execute(
                () -> {
                    System.out.println("Entered Async zone executing in thread: "+ Thread.currentThread().getName());
                    System.out.println("Simulating long running op via Thread sleep() started on "+ new Date().toString());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(MyAsyncRESTResource.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    System.out.println("Completed Long running op on "+new Date().toString());
                    System.out.println("Exiting Async zone executing in thread: "+ Thread.currentThread().getName());

                    //creating a dummy instance of our model class (Student)

                    Student stud = new Student(input, "Abhishek", "Apr-08-1987");
                    resp.resume(Response.ok(stud).build());
                }
        );

        System.out.println("Exit MyAsyncRESTResource/asyncMethod() and returned thread "+Thread.currentThread().getName()+" back to thread pool");
    }

The JAX-RS Client API also has asynchronous capabilities but they have not been discussed in the post. They are definitely worth a look!

Websocket 1.0

The Websocket API is a brand new addition to the Java EE arsenal (introduced in Java EE 7). It facilitates bi-directional (both server and client initiated) communication which is also full duplex in nature (either the client or server can send messages to each other at any time).

In order to send async messages using the Websocket API, one needs to use the getAsyncRemote method available on the javax.websocket.Session interface. Internally, this is nothing but an instance of the nested interface of the javax.websocket.RemoteEnpoint – javax.websocket.RemoteEnpoint.Async. Calling the regular sendXXX methods on this would result in the sending process being executed in a separate thread. This is particularly useful when you consider exchange of large messages or handling large numbers of websocket clients to whom the messages need to be sent. The method wither returns a java.util.concurrent.Future object or one can register a callback in the form of a javax.websocket.SendHandler interface implementation.

public void sendMsg(@Observes Stock stock) {
        System.out.println("Message receieved by MessageObserver --> "+ stock);
        System.out.println("peers.size() --> "+ peers.size());
        peers.stream().forEach((aPeer) -> {
            //stock.setPrice();

                            aPeer.getAsyncRemote().sendText(stock.toString(), (result) -> {
                System.out.println("Message Sent? " + result.isOK());
                System.out.println("Thread : " + Thread.currentThread().getName());
            });

        });
    }

Concurrency Utilities 1.0

The Java EE Concurrency Utilities is another great addition to Java EE 7. It provides a standard way of spawning threads – the good part is that these are container managed and not just isolated/orphan threads about which the container has no contextual information.

In general, the Concurrency Utilities 1.0 provide a few standard constructs for execution of asynchronous tasks in separate threads. These are as follows – javax.enterprise.concurrent.ManagedExecutorService  and javax.enterprise.concurrent.ManagedScheduledExecutorService.

In order to start a new task in a separate thread, one can use the ManagedExecutorService interface to submit a Runnable. In addition to implementing the Runnable interface, a class can also implement the javax.enterprise.concurrent.ManagedTask interface and provide a  javax.enterprise.concurrent.ManagedTaskListener implementation in order to listen to life  cycle changes to the task submitted via the ManagedExecutorService.

@Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        System.out.println("Enter AConcurrencyUtilsExample/doGet executing in thread "+ Thread.currentThread().getName());
        System.out.println("initiating task . . . ");
        mes.execute(new AManagedTask());
        System.out.println("Exit AConcurrencyUtilsExample/doGet and returning thread "+ Thread.currentThread().getName() +" back to pool");
    }

Servlet 3.0

Asynchronous HTTP was introduced in Servlet 3.0 (part of Java EE 6) which basically provided the capability to execute the request in separate thread and suspend the original thread which handled the client invocation.

The key player here is the javax.servlet.AsyncContext interface. In order to initiate asynchronous processing, the startAsync method of the java.servlet.ServletRequest interface is called. In order to execute the core logic, a java.lang.Runnable object needs to be submitted to the start method of the AsyncContext interface. One can choose to attach a listener by implementing the javax.servlet.AsyncListener in order to receive callback notifications during specific times of the Async task execution.

@Override

    public void doGet(HttpServletRequest req, HttpServletResponse resp) {

        PrintWriter writer = null;
        try {
            writer = resp.getWriter();
        } catch (IOException ex) {
            Logger.getLogger(MyAsyncServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
        //System.out.println("entered doGet()");
        writer.println("ENTERING ... " + MyAsyncServlet.class.getSimpleName() + "/doGet()");
        writer.println("Executing in Thread: " + Thread.currentThread().getName());
        //step 1
        final AsyncContext asyncContext = req.startAsync();

        //step 2
        asyncContext.addListener(new CustomAsyncHandler(asyncContext));

        //step 3
        asyncContext.start(
                () -> {
                    PrintWriter logger = null;
                    try {
                        logger = asyncContext.getResponse().getWriter();
                    } catch (IOException ex) {
                        Logger.getLogger(MyAsyncServlet.class.getName()).log(Level.SEVERE, null, ex);
                    }

                    logger.println("Long running Aync task execution started : " + new Date().toString());

                    logger.println("Executing in Thread: " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        Logger.getLogger(MyAsyncServlet.class.getName()).log(Level.SEVERE, null, e);
                    }

                    logger.println("Long task execution complete : " + new Date().toString());

                    logger.println("Calling complete() on AsyncContext");

                    //step 4
                    asyncContext.complete();
                }
        );

        writer.println("EXITING ... " + MyAsyncServlet.class.getSimpleName() + "/doGet() and returning initial thread back to the thread pool");

    }

EJB 3.1

Typically, (prior to EJB 3.1) EJB Message Driven Beans were used to fulfill async related requirements. A MDB bean listens to messages sent to a javax.jms.Destination (a Queue or Topic) and executes the required business logic – this might be anything from sending an email to initiating an order processing task. The important thing to understand is that the client which sends the message to the Queue in the first place is unaware of the MDB (decoupled) and does not have to wait/remain blocked until the end of the job (email receipt or order processing confirmation).

EJB 3.1 (part of Java EE 6) introduced the javax.ejb.Asynchronous annotation. This can be placed on a EJB Session bean (Stateless, Stateful or Singleton) class (makes all the methods Asynchronous) or at the method level itself – in case fine grained control is needed. A method with the @Asynchronous annotation can either return void (fire and forget) or an instance of java.util.concurrent.Future if the async method result needs to be tracked – this can be done by calling the Future.get() – the thing to note is that the get method itself is blocking in nature.

@Asynchronous
        public Future<String> asyncEJB2(){

        System.out.println("Entered MyAsyncEJB/asyncEJB2()");
       System.out.println("MyAsyncEJB/asyncEJB2() Executing in thread: "+ Thread.currentThread().getName());
        System.out.println("Pretending as if MyAsyncEJB/asyncEJB2() is doing something !");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {
            java.util.logging.Logger.getLogger(MyAsyncEJB.class.getName()).log(Level.SEVERE, null, ex);
        }

        System.out.println("Exiting MyAsyncEJB/asyncEJB2()");
        return new AsyncResult("Finished Executing on "+ new Date().toString());

    }

This was a rather brief preview of Java EE capabilities. These APIs and specifications are functionally rich and it is hard cover all of them via a blog post! I hope this piques your interest and gives you a starting point to explore further.

Cheers!

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button