Monday 4 August 2014

Asynchronous Processing

Before discussing about Asynchronous processing, lets observe the below Servlet Application.

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = {"/ProcessRequest"})
public class ProcessRequest extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res)throws IOException, ServletException{
        try(PrintWriter out = res.getWriter()){
            String time = req.getParameter("time");
            int wait = Integer.parseInt(time);
            
            String threadName = Thread.currentThread().getName();
            long startTime = System.currentTimeMillis();
            out.println("Thread " + threadName + " started at " + startTime);
            
            Thread.sleep(wait);
            
            long endTime = System.currentTimeMillis();
            out.println("Thread " + threadName + " finished at " + endTime);
            out.println("Total time taken is " +(endTime-startTime) + " Milli Seconds");
        }
        catch(InterruptedException e){
            
        }
    }
}

Output

Run the above servlet like below.

time is passed as query string. Servlet simply reads the time parameter in query string and waits for that much time, and sends the response to the client.
In the above servlet are we really doing anything with request and response objects ?

No, But the thread associated with this request can't do anything until the sleep finishes. These kind of long running tasks leads to thread starvation. Since our servlet thread is blocked until all the processing is done, if server gets a lot of requests to process, it will hit the maximum servlet thread limit and further requests will get Connection Refused errors.

As an Application developer, you must ensure that no threads associated with a request are sitting idle, so the container can use them to process new requests. Asynchronous processing provides a facility to assign these blocking operations to a new thread and retuning the thread associated with the request immediately to the container.

If a servlet or a filter reaches a potentially blocking operation when processing a request, it can assign the operation to an asynchronous execution context and return the thread associated with the request immediately to the container without generating a response. The blocking operation completes in the asynchronous execution context in a different thread, which can generate a response or dispatch the request to another servlet.

Example
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.AsyncContext;

@WebServlet(urlPatterns = {"/ProcessRequest"}, asyncSupported=true)
public class ProcessRequest extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res)throws IOException, ServletException{
            final AsyncContext acontext = req.startAsync();
            
            String threadName = Thread.currentThread().getName();
            long startTime = System.currentTimeMillis();
            System.out.println("Thread " + threadName + " started at " + startTime);

            acontext.start(new Runnable() {

                public void run() {
                    String time = req.getParameter("time");
                    int wait = Integer.parseInt(time);
                    
                    try{
                        Thread.sleep(wait);
                    }
                    catch(InterruptedException e){
                        
                    }
                    HttpServletResponse response = (HttpServletResponse)acontext.getResponse();
                    try(PrintWriter out = response.getWriter()) {
                        out.println("I am done");
                    }
                    catch(Exception e){
                        
                    }
                    acontext.complete();
                }
            });
            
            long endTime = System.currentTimeMillis();
            System.out.println("Thread " + threadName + " finished at " + endTime);
            System.out.println("Total time taken is " +(endTime-startTime) + " Milli Seconds");
       
    }
}

Run the above servlet like below.

As you see the console logs, you can observe the below information messages immediately.

Info: Thread http-listener-1(5) started at 1405140693455
Info: Thread http-listener-1(5) finished at 1405140693456
Info: Total time taken is 1 Milli Seconds

After 10 seconds you can see the response in your browser.


WebServlet(urlPatterns = {"/ProcessRequest"}, asyncSupported=true)
public class ProcessRequest extends HttpServlet {…}
To enable asynchronous processing on a servlet, set the parameter asyncSupported to true on the @WebServlet annotation as follows:

final AsyncContext acontext = req.startAsync();
above statement is used to get Asynchronous context. The javax.servlet.AsyncContext class provides the functionality that you need to perform asynchronous processing inside service methods. This call puts the request into asynchronous mode and ensures that the response is not committed after exiting the service method.

acontext.start(new Runnable(){..});
The container provides a different thread in which the blocking operation can be processed.

Servlet API provides below methods to support Asynchronous processing.
      AsyncContext getAsyncContext()
      boolean isAsyncStarted()
      boolean isAsyncSupported()
      AsyncContext startAsync()
      AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)





Prevoius                                                 Next                                                 Home

No comments:

Post a Comment