The Java EE 7 Tutorial
17.13 Nonblocking I/O
Web containers in application servers normally use a server thread per client request. To develop scalable web applications, you must ensure that threads associated with client requests are never sitting idle waiting for a blocking operation to complete. Asynchronous Processing provides a mechanism to execute application-specific blocking operations in a new thread, returning the thread associated with the request immediately to the container. Even if you use asynchronous processing for all the application-specific blocking operations inside your service methods, threads associated with client requests can be momentarily sitting idle because of input/output considerations.
For example, if a client is submitting a large HTTP POST request over a slow network connection, the server can read the request faster than the client can provide it. Using traditional I/O, the container thread associated with this request would be sometimes sitting idle waiting for the rest of the request.
Java EE provides nonblocking I/O support for servlets and filters when processing requests in asynchronous mode. The following steps summarize how to use nonblocking I/O to process requests and write responses inside service methods.
-
Put the request in asynchronous mode as described in Asynchronous Processing.
-
Obtain an input stream and/or an output stream from the request and response objects in the service method.
-
Assign a read listener to the input stream and/or a write listener to the output stream.
-
Process the request and the response inside the listener's callback methods.
Table 17-4 and Table 17-5 describe the methods available in the servlet input and output streams for nonblocking I/O support. Table 17-6 describes the interfaces for read listeners and write listeners.
Table 17-4 Nonblocking I/O Support in javax.servlet.ServletInputStream
Method | Description |
---|---|
|
Associates this input stream with a listener object that contains callback methods to read data asynchronously. You provide the listener object as an anonymous class or use another mechanism to pass the input stream to the read listener object. |
|
Returns true if data can be read without blocking. |
|
Returns true when all the data has been read. |
Table 17-5 Nonblocking I/O Support in javax.servlet.ServletOutputStream
Method | Description |
---|---|
|
Associates this output stream with a listener object that contains callback methods to write data asynchronously. You provide the write listener object as an anonymous class or use another mechanism to pass the output stream to the write listener object. |
|
Returns true if data can be written without blocking. |
Table 17-6 Listener Interfaces for Nonblocking I/O Support
Interface | Methods | Description |
---|---|---|
|
|
A |
|
|
A |
17.13.1 Reading a Large HTTP POST Request Using Nonblocking I/O
The code in this section shows how to read a large HTTP POST request inside a servlet by putting the request in asynchronous mode (as described in Asynchronous Processing) and using the nonblocking I/O functionality from Table 17-4 and Table 17-6.
@WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true) public class AsyncIOServlet extends HttpServlet { @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { final AsyncContext acontext = request.startAsync(); final ServletInputStream input = request.getInputStream(); input.setReadListener(new ReadListener() { byte buffer[] = new byte[4*1024]; StringBuilder sbuilder = new StringBuilder(); @Override public void onDataAvailable() { try { do { int length = input.read(buffer); sbuilder.append(new String(buffer, 0, length)); } while(input.isReady()); } catch (IOException ex) { ... } } @Override public void onAllDataRead() { try { acontext.getResponse().getWriter() .write("...the response..."); } catch (IOException ex) { ... } acontext.complete(); } @Override public void onError(Throwable t) { ... } }); } }
This example declares the web servlet with asynchronous support using the @WebServlet
annotation parameter asyncSupported=true
. The service method first puts the request in asynchronous mode by calling the startAsync()
method of the request object, which is required in order to use nonblocking I/O. Then, the service method obtains an input stream associated with the request and assigns a read listener defined as an inner class. The listener reads parts of the request as they become available and then writes some response to the client when it finishes reading the request.