17.1 Don't Use SingleThreadModel

javax.servlet.SingleThreadModel is a marker interface available to servlet developers that pushes responsibility for thread safety onto the servlet engine. Essentially, if your servlet implements SingleThreadModel, the servlet engine creates a separate servlet instance for each concurrent request using the servlet. SingleThreadModel does not even guarantee thread safety, since the resulting servlet instances can still access classes and data at the same time. However, SingleThreadModel does guarantee that more resources will be used than are needed, as maintaining the multiple instances has some cost to the servlet engine.

Instead of using SingleThreadModel, concentrate on writing a thread-safe multi-threaded servlet. See Section 10.4.2 for details on writing efficient thread-safe code. Writing your servlet with big synchronized blocks may be highly thread-safe but won't scale. For example, the following rather extreme implementation synchronizes the entire servlet activity:

public class MyVeryThreadSafeServlet extends HttpServlet {
  ...
  public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ... {
    synchronized(this)
    {
      //Everything happens in the synchronized block so that
      //we have a thread-safe servlet
      ...
    }
  }
  ...

With this servlet implementation, every HTTP request processed by this servlet would have to go through the same synchronized monitor from start to finish, so only one request could be processed at a time, regardless of how many threads you spawned for this servlet. Other concurrent requests would wait until the current request was processed before starting execution. If your servlet received an average of one request per second and the processing took an average of half a second, then this implementation is adequate.

However, if your servlet received an average of one request per second and the processing took an average of two seconds, then your servlet can process an average of only one request every two secondsi.e., half the requests. This is independent of the CPU capability of the server. You could have plenty of spare CPU power; indeed, if you had eight CPUs, this implementation would leave seven of them mostly idle. The result is that the server listen queue would fill up quickly, and your servlet (actually, the TCP stack) would simply reject half the connections. To sum up:

  • Don't use SingleThreadModel.

  • Make the servlet thread-safe.

  • Try to minimize the amount of time spent in synchronized code while still maintaining a thread-safe servlet.

  • Use as many servlet threads as are needed to handle the request throughput.

  • Where a limited number of services must be distributed among the servlet threads (for example, database connections), use resource pools (such as database connection pools) to provide optimal service distribution.

  • The larger the request service time, the greater the number of threads you need to maintain adequate response times for a given rate of requests.