[ Team LiB ] Previous Section Next Section

Making JSPs and Servlets Thread-Safe

One of the key features for high-performance server applications is the heavy use of threads. The Java networking classes do all their data transfer via blocking operations, meaning the executing thread waits until the data has been transferred. Many times, however, the server can be doing other things while waiting for the data to transmit. Most servers generally have one thread per client, with each thread listening for incoming requests. Some servers might also have a pool of threads to execute requests (the reader thread hands the request off to an execution thread and then looks for more incoming requests).

New I/O

graphics/bytheway_icon.gif

JDK 1.4 introduced a new IO system called NIO (New I/O), which includes nonblocking IO. With nonblocking IO, you don't have to dedicate a separate thread per connection. For high-volume applications, NIO lets you reduce the number of active threads, conserving precious system resources. Of course, to really take advantage of NIO with JSP and servlets, you need a JSP/servlet container that supports NIO.

At the time of writing this book, Tomcat 5 does not support NIO, because it works on JDK 1.3. However, more than likely you will see a patch for it in the very near future (maybe even by the time this book is published).


Almost all JSP and servlet engines are multithreaded, and by default, JavaServer Pages are assumed to be thread-safe. Unless you specify otherwise, multiple threads might be executing a JavaServer Page at the same time. The <%@ page isThreadSafe="false"%> directive tells the JSP engine that a JavaServer Page is not thread-safe. If you expect fairly high volume on your JSP, you should make sure it is thread-safe. Restricting a JSP to a single thread can really slow things down.

Servlets are also assumed to be multithreaded, but there is no simple directive to mark the servlet as not being thread-safe. Instead, you must declare either the service method or the individual doPost and doGet methods as being synchronized. Marking the whole method as synchronized is a brute-force method, just like marking an entire JSP as non-thread-safe. You are much better off finding the places where threading is a problem and fixing them.

There are certain things you can look for when searching for areas of your program that might not be thread-safe:

  • Does the JSP access a variable defined with the <%! %> tag?

  • Does the servlet access any member variables?

  • Does the JSP or servlet modify the contents of an object stored in either the session or application (ServletContext) objects?

  • Does the JSP or servlet use any libraries that might not be thread-safe?

Even if the answer to any of these questions is "yes," you don't necessarily have a threading issue. If you are always reading the value of a member variable, you probably don't have a threading issue. Sometimes you set up some variables during the initialization of a JSP or servlet and then don't change the value during execution. You can safely assume that multiple threads can read the value of the variables without any problems.

When you store an object in the session or the application object, you need to consider the circumstances in which multiple threads might be using the same data. Because each browser has its own session, the only threading issues for objects stored in the session will occur when the browser requests several JSPs or servlets at once. When you store objects in the application object, consider whether another thread might also be trying to store the same object.

Often you create an object that is shared across multiple servlets, but you create the object only if there isn't one already stored in the application object. When you discover that you need to create the object, synchronize on the application object and then check again to see whether the object needs to be created. Then, within the synchronized block, create the shared object. Listing 24.2 shows a segment of code that creates a shared object.

Listing 24.2 Code Fragment to Create a Shared Object
// Synchronize on the application object
    synchronized(context)
    {
// See whether the connection pool has already been created.
        IConnectionPool pool = (IConnectionPool) context.getAttribute(
            "connectionPool");

// If not, the pool must be created.
        if (pool == null)
        {

// Make sure the database driver is available.
            try {
                Class.forName("org.gjt.mm.mysql.Driver").
                    newInstance();
            } catch (Exception exc) {
                getServletContext().log(
                    "Error loading JDBC driver", exc);
            }

// Create the connection pool and store it in the application object.
            pool = new SimpleConnectionPool(
                "jdbc:mysql://localhost/usingjsp",
                "", "");
            context.setAttribute("connectionPool", pool);
        }
    }

Because the test for the presence of the object is in the same synchronized block as the code that creates the object, you can be sure that only one thread actually creates the object.

You must also take special care with the objects you store in the application and session objects. If you store objects that aren't thread-safe, you must synchronize any method calls that modify the state of those objects. Most of the objects in the Java API, such as Vector, ResultSet, Connection, and so on, are thread-safe. If you use third-party libraries, consult your documentation to find out whether any objects are known to be unsafe for threading.

    [ Team LiB ] Previous Section Next Section