Write thread-safe servlets
February 21, 2008 by muralis
A thread is a single execution process; in other words, an individual, sequential flow of control within a program. When we say that a program is multi-threaded, we are not implying that the program runs two separate instances simultaneously (as if you concurrently executed the program twice from the command line). Rather, we are saying that the same instance (executed only once) spawns multiple threads that process this single instance of code. This means that more than one sequential flow of control runs through the same memory block.
So what do we mean by thread-safe, you ask? When multiple threads execute a single instance of a program and therefore share memory, multiple threads could possibly be attempting to read and write to the same place in memory. Let’s look at an example. If we have a multi-threaded program, we will have multiple threads processing the same instance (see Figure 1).
What happens when Thread-A examines variable instanceVar? Notice how Thread-B has just incremented instanceVar. The problem here is Thread-A has written to the instanceVar and is not expecting that value to change unless Thread-A explicitly does so. Unfortunately Thread-B is thinking the same thing regarding itself; the only problem is they share the same variable. This issue is not unique to servlets. It is a common programming problem only present when multi threading an application. You are probably thinking; “Well I didn’t ask for multithreading. I just want a servlet!” And a servlet is what you have. Let me introduce you to our friend the servlet container.
Your servlet container is no dummy
A lot of magic happens between the Web browser’s HTTP request and the code we write within the doGet() and doPost() methods. The servlet container makes this “magic” possible. Like any Java program, the servlet must run within a JVM, but for a Web application, we also have the complexity of handling HTTP requests—that’s where the servlet container comes in. The servlet container is responsible for your servlets’ creation, destruction, and execution; the sequence of these events is referred to as the servlet’s lifecycle.
Synchronization Issues
By default, the service method of the JSP page implementation class that services the client request is multithreaded. Thus, it is the responsibility of the JSP page author to ensure that access to shared state is effectively synchronized. There are a couple of different ways to ensure that the service methods are thread-safe. The easy approach is to include the JSP page directive:
This causes the JSP page implementation class to implement the SingleThreadModel interface, resulting in the synchronization of the service method, and having multiple instances of the servlet to be loaded in memory. The concurrent client requests are then distributed evenly amongst these instances for processing in a round-robin fashion, as shown below:
The downside of using this approach is that it is not scalable. If the wait queue grows due to a large number of concurrent requests overwhelming the processing ability of the servlet instances, then the client may suffer a significant delay in obtaining the response.
A better approach is to explicitly synchronize access to shared objects (like those instances with application scope, for example) within the JSP page, using scriptlets:
synchronized (application) {
SharedObject foo = (SharedObject)
application.getAttribute(”sharedObject”);
foo.update(someValue);
application.setAttribute(”sharedObject”,foo);
}
Thread-Safe Collections
The key difference between the historical collection classes and the new implementations within the Collections Framework is the new classes are not thread-safe. This was done such that if you don’t need the synchronization, you don’t use it, and everything works much faster. If, however, you are using a collection in a multi-threaded environment, where multiple threads can modify the collection simultaneously, the modifications need to be synchronized. The Collections class provides for the the ability to wrap existing collections into synchronized ones with another set of six methods:
* Collection synchronizedCollection(Collection collection)
* List synchronizedList(List list)
* Map synchronizedMap(Map map)
* Set synchronizedSet(Set set)
* SortedMap synchronizedSortedMap(SortedMap map)
* SortedSet synchronizedSortedSet(SortedSet set)
Unlike when making a collection read-only, you synchronize the collection immediately after creating it. You also must make sure you do not retain a reference to the original collection, or else you can access the collection unsynchronized. The simplest way to make sure you don’t retain a reference is to never create one:
Set set = Collection.synchronizedSet(new HashSet());
Making a collection unmodifiable also makes a collection thread-safe, as the collection can’t be modified. This avoids the synchronization overhead.

