Asynchronous servlet best practices
The asynchronous servlet feature enables us to process incoming requests and responses without being bound to the original thread that initiated the request.
Consider the following best practices when using asynchronous servlets:
- Applications should not spawn a new thread for each asynchronous operation needed. At a minimum, applications should use a thread pool or use the AsyncContext start(Runnable) method.
- On the client/browser side, we can use AJAX to enable certain portions of the page to be updated asynchronously.
- The servlet container ensures that calls to complete or dispatch do not start until the web container thread that initiated the startAsync command exists. However, the servlet container does not handle multiple threads using the same request and response simultaneously. The application can handle its own concurrency or synchronization issues in this case, but it is not recommended because it can be prone to deadlock or race conditions. If the dispatch or complete method is called from a customer-created thread or runnable started with start(Runnable), then dispatch or complete can start immediately on a new thread and any further modifications to the request or response from the thread that initiated these calls is dangerous. Two threads will have access to the request and response, which can have indeterminate results if both threads are modifying those objects. Therefore, do not call any methods on the request or response after a dispatch from the same thread that called the dispatch. Do not call any methods on the request or response after a complete operation is called.
- Asynchronous listeners have an onTimeout method that starts when a time limit is reached for the asynchronous operation. However, the asynchronous operation might still be running on one thread while the onTimeout runs on a different thread. This scenario is the most common way that multiple threads inadvertently use the same request and response simultaneously. A simple approach to this scenario is to use a shared AtomicBoolean method from both the AsyncListener and the asynchronous operation, as follows:
AtomicBoolean isOkayToRun = (AtomicBoolean) request.getAttribute("isOkayToRun"); if (isOkayToRun.setAndGet(false)){ //do a dispatch }With this approach, only one thread can obtain access to write to the response.- The web container attempts to cancel any runnables that are queued by calls to the start(Runnable) method when the timeout is reached. However, runnables that have already started cannot be interrupted because the interruption leads to leaking memory.
- The number of threads doing the timeout notifications is very small. Attempting any intensive operation or any write operation from a timeout is not recommended because even a small write operation might take awhile if the client has a slow connection. When we disable the asynchronous timeout, it is easier to run into OutOfMemory errors or to exhaust the number of TCP channel connections. The default timeout is 30 seconds.
- We can configure some asynchronous servlet options, such as timeout settings and the AsyncContext start(Runnable) method, in the administrative console by clicking Servers > Server Types > WebSphere application servers > server > Web Container Settings > Web container. Refer to the Web container settings topic to learn about configuring the Web container.
Important: Asynchronous request dispatcher (ARD) and remote request dispatcher (RRD) are not supported when using asynchronous servlets.
Tip: View the Web application counters topic to learn about metrics for asynchronous servlets.
Related:
Java Servlet considerations Web applications: Resources for learning Web application counters Web container settings