1

I am exploring async servlets using Spring boot. As far as I understand, async servlets are used to execute long running tasks in a thread other than the one which container launches to handle the request, so that container can use its own thread for handling other connections. Based on this understanding, I tried the following code:

@WebServlet(asyncSupported = true, urlPatterns = "/demo")
@Component
public class demo extends HttpServlet {



    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        final AsyncContext context = request.startAsync();
        ServletOutputStream stream = response.getOutputStream();
        WriteListener listener = new WriteListener() {

            @Override
            public void onWritePossible() throws IOException {
                System.out.println(Thread.currentThread().getId());
                ServletOutputStream output = context.getResponse().getOutputStream();
                if (output.isReady()) {
                    try {
                        TimeUnit.SECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    output.print("Heloooooooooo");
                }
                context.complete();
            }

            @Override
            public void onError(Throwable throwable) {
                throwable.printStackTrace(System.err);
                context.complete();
            }
        };

        stream.setWriteListener(listener);
        System.out.println(Thread.currentThread().getId());

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
        // TODO Auto-generated method stub
    }

}

But the problem is that onWritePossible method is being invoked by the same thread which ran doGet. Shouldn't it have been different ?

mzc
  • 3,265
  • 1
  • 20
  • 25
redeemed
  • 471
  • 7
  • 22
  • Typically, there will be two requests. One for the main page and another for the websocket (fired by javascript once the page loads) – lance-java Nov 10 '15 at 15:17
  • This isn't about websockets . It's an Async Servlet and i am trying to access it via http://localhost:8080/demo – redeemed Nov 10 '15 at 17:11

2 Answers2

1

In your doGet method you have created an AsyncContext and it is your responsibility to pass it further to a different thread that will (at a later time) complete the processing by setting the result - servlet container will not create a new thread for you.

After AsyncContext is passed to a different thread, doGet can immediately return freeing up the servlet container's executor thread to serve new requests.

An example based on your code:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
    final AsyncContext context = request.startAsync();
    System.out.println("Servlet container thread before async started: " 
        + Thread.currentThread().getName());
    new Thread(new Runnable() {
        @Override
        public void run() {
                try {
                    System.out.println("New thread started: " 
                         + Thread.currentThread().getName());
                    ServletOutputStream output = context.getResponse().getOutputStream();
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println("New thread writing response: " 
                        + Thread.currentThread().getName());
                    output.print("Hi!");
                    context.complete();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
        }
    }).start();
    System.out.println("Servlet container thread returning: " 
        + Thread.currentThread().getName());
}

Output:

Servlet container thread before async started: http-nio-8080-exec-1
Servlet container thread returning: http-nio-8080-exec-1
New thread started: Thread-3
New thread writing response: Thread-3

If you use Spring Boot, you can implement a Controller which returns a Callable and Spring Framework will make sure that the Callable is executed in a different thread whose lifecycle is managed by Spring.

If you want to do it without Spring (which is also fine), it is typically done by placing the AsyncContext in the queue and having an ExecutorService consuming the queued requests.

mzc
  • 3,265
  • 1
  • 20
  • 25
-1

Your understanding is a bit off. The benefit of async methods as they're typically used is to not consume an additional thread, while also not blocking the thread handling the request. To get any real benefit out of them, you need to utilize non-blocking API's when performing IO.

This question, while asked in the context of .NET technologies, should shed some light.

Community
  • 1
  • 1
w.brian
  • 16,296
  • 14
  • 69
  • 118