MultithreadingS2C Home « Multithreading

In the last lesson we looked at the three scopes we can use with our servlets, these being the request, session and context scopes. What we didn't talk about were situations where multiple threads access resources within a scope, generally attributes, and how this affects the values held therein. In this lesson we discuss multithreading in web applications, whether a scope is thread safe, and if not, when and how we can protect resources within that scope from concurrent access.

The main drive of this lesson will be to discuss thread safety with regards to attributes and the various scopes they reside in. Before we do this we will discuss the other resources available in Java as the rules for these resources apply regardless of scope.

Class Variables

Class variables are not thread safe because all threads share the same method area, and the method area is where class variables are stored. This means that multiple threads can attempt to use the same class variables concurrently and so thread safety cannot be guaranteed.

Instance Variables

Instance variables are not thread safe because all threads share the same heap, and the heap is where instance variables are stored. This means that multiple threads can attempt to use the same instance variables concurrently and so thread safety cannot be guaranteed. There is also no certainty that a client accessing the same URL will even get the same instance variables. It's generally better to use session attributes in place of instance variables, but if for whatever reason you really have to use an instance variable then you will need to add synchronization to guarantee thread safety, which is of course a hit to performance.

Local Variables

Local variables which consist of method parameters, return values and variables declared within methods reside on the stack and the JVM allocates each thread its own stack. Therefore a thread only has access to its own stack and knows nothing about local variables belonging to another thread. What this means is that we don't have to worry about thread safety with regards to local variables as they are inherently thread safe by design.

Request Attributesgo to top of page Top

In the Request & Response - One Thread Per Request section we looked at how the container creates a new java thread every time a servlet request is received. The thread will have its own stack for local variables as discussed above. These will include the method parameters to the service() method (ServletRequest and ServletResponse objects), the method parameters to any invoked doXXX() method (HttpServletRequest and HttpServletResponse objects), as well as any attributes attached to the ServletRequest or HttpServletRequest object. What this means is that any request attributes we create whether they are in the service() method, or an invoked doXXX() method, can only ever be accessed by this thread and are therefore thread safe.

The following slideshow shows three client requests accessing a servlet and the resources that can be accessed. Press the button below to step through the slideshow:

reqattr 1 reqattr 2 reqattr 3

Client 1 has clicked on a link that points to a resource that is a servlet rather than a static HTML page, so the web server directs the HTTP request to our web container and creates a new thread (Thread1) for this request. The service() method, any invoked doXXX() method, the request object and any request attributes reside in their own stack allocated by the JVM.

Client 2 has clicked on a link that points to a resource that is a servlet rather than a static HTML page, so the web server directs the HTTP request to our web container and creates a new thread (Thread2) for this request. The service() method, any invoked doXXX() method, the request object and any request attributes reside in their own stack allocated by the JVM.

Client 2 has clicked on a link that points to a resource that is a servlet rather than a static HTML page, so the web server directs the HTTP request to our web container and creates a new thread (Thread3) for this request. The service() method, any invoked doXXX() method, the request object and any request attributes reside in their own stack allocated by the JVM.

Press the button below to cycle through our Request Attribute Threading slideshow.


We use the ServletRequest type when working with request attributes. The following code snippet shows request attributes being used:


public void doGet(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException { 
    // Get request attributes
    String getAttr1 = (String) req.getAttribute("name"));
    String getAttr2 = (String) req.getAttribute("age"));
    // Get all request attributes
    Enumeration<String> getRequestAttributes = req.getAttributeNames();
    // Set request attributes
    req.setAttribute("name", "charlie");
    req.setAttribute("age", "22");
    // Remove request attributes
    req.removeAttribute("name");
    req.removeAttribute("age");
}

Session Attributesgo to top of page Top

In the Attributes & Scope - Session Scope section we learnt that if we require sessions, then the container uses the HttpSession interface to create a session object to use between an HTTP client and an HTTP server. This is achieved using the overloaded getSession() method of the HttpSession interface and the container keeps track of session objects using a unique session identifier that identifies each individual session.

You would think then that using this unique session identifier and even if multiple servlets are invoked, a client can only have one request running at a time and as we now know request attributes are thread safe and run in their own stack. This would seem to infer that session attributes are also thread safe as only one request is being processed for a client at any given time. Sadly this is not the case as we can have a scenario where more than one request comes in from the client. How is this possible? Well the client can just open another browser window and invoke the servlet where the session was created. This could happen for any number of reasons, including a slow response to the initial request and the user gets fed up with waiting, we have all done this at some point. The request attributes are still thread safe because they are running in their own stacks but the servlet will see we have an exisiting session and use this. This could mean an overlap of retrieving and updating session attributes, via the two requests, making session attributes inherently unsafe.

The following slideshow shows such a scenario. Press the button below to step through the slideshow:

sessattr 1 sessattr 2 sessattr 3

The service() method invokes one of the doXXX() methods. Within the doXXX() method we create our session object using the getSession() method and create some session attributes.


The service() method invokes one of the doXXX() methods. Within the doXXX() method we retrieve our session object using the getSession() method and try to update some session attributes. The user is getting no response from the servlet.


The user decides to open a new browser window and does another request which will be a new thread and a new request object within another stack. The service() method invokes one of the doXXX() methods. Within the doXXX() method we retrieve our session object using the getSession() method and try to update some session attributes. Both requests now have access to the same session object making the session attributes unsafe.

Press the button below to cycle through our Session Attribute Threading slideshow.


So how can we protect our session attributes from the above scenario? Well just like with any concurrent processing where we need to ensure only one thread has access to a resource at any given time we can use synchronization. To protect our session attributes we need to synchronize on the HttpSession object and do our setAttribute() method updates there. The following code snippet shows session attributes being updated within a synchronization block:


HttpSession session = HttpServletRequest.getSession();

synchronized(session) {
    session.setAttribute("name", "charlie");
    session.setAttribute("age", "22");
}

We would also clearly need to synchronize when removing attributes using the removeAttribute() method. The following code snippet shows session attributes being removed within a synchronization block:


HttpSession session = HttpServletRequest.getSession();

synchronized(session) {
    session.removeAttribute("name");
    session.removeAttribute("age");
}

If it's important that users don't get session attributes during updates then our getAttribute() and getAttributeNames() methods should also be synchronized. The following code snippet shows session attributes being output to a console and stored in an Enumeration from within a synchronization block:


HttpSession session = HttpServletRequest.getSession();

synchronized(session) {
    System.out.println(session.getAttribute("name"));
    System.out.println(session.getAttribute("age"));
    // Get all session attributes
    Enumeration<String> getSessionAttributes = session.getAttributeNames();
}

Context Attributesgo to top of page Top

Context attributes are application wide and so can be used by any servlet in the web application. This also means they are the most likely to be affected by concurrent update as potentially any request from a client to the web application could involve an update to a context attribute.

The following slideshow shows context attributes being set within two applications. Whenever any of the servlets access the same context attributes there is a possibility of concurrent access. Press the button below to step through the slideshow:

rscope 1 cattr 2 cattr 3 cattr 4

Client 1 requests ServletA which now has access to the context object of web app 1 and updates context attributes.

Client 1 requests ServletB which now has access to the context object of web app 1 and updates context attributes.

Client 2 requests ServletB which now has access to the context object of web app 1 and updates context attributes.

Client 2 requests ServletC which now has access to the context object of web app 1 and updates context attributes.

Press the button below to cycle through our Context Attribute Threading slideshow.


So how can we protect our context attribues from the above scenario? It really depends on what you are using the context attributes for. If you intend these attributes as read only then you can put setAttribute() method updates within the init() servlet lifecycle method. You would then have to ensure your programmers were aware that the setAttribute() method update is not to be used within the service() and any doXXX() methods. So this would have to be enforced as a programming standard and lets face it you're now hardcoding read only attributes and enforcing standards when you could add these declaratively in the DD using the <context-param> top-level element in conjunction with its <param-name> and <param-value> sub-level elements. So maybe not the most elegant solution.

The alternative just like with any concurrent processing where we need to ensure only one thread has access to a resource at any give time and what we do with session attributes is to use synchronization. Unlike the HttpSession object we don't create our have direct access to the ServletContext object, so what do we synchronize on? To protect our context attributes we need to synchronize on the getServletContext() method and do our setAttribute() method updates there. The following code snippet shows context attributes being updated within a synchronization block:


synchronized(getServletContext()) {
    getServletContext().setAttribute("name", "charlie");
    getServletContext().setAttribute("age", "22");
}

We would also clearly need to synchronize when removing attributes using the removeAttribute() method. The following code snippet shows context attributes being removed within a synchronization block:


synchronized(getServletContext()) {
    getServletContext().removeAttribute("name");
    getServletContext().removeAttribute("age");
}

If it's important that users don't get context attributes during updates then our getAttribute() and getAttributeNames() methods should also be synchronized. The following code snippet shows context attributes being output to a console and stored in an Enumeration from within a synchronization block:


synchronized(getServletContext()) {
    System.out.println(getServletContext().getAttribute("name"));
    System.out.println(getServletContext().getAttribute("age"));
    // Get all servletContext attributes
    Enumeration<String> getContextAttributes = getServletContext().getAttributeNames();
}

Obviously with context attributes you have to be very careful with synchronization as these attributes are application wide and synchronization is a hit to performance. Also if context attributes are in constant need of updating they can cause bottlenecks within a web application and seriously degrade performance. So in these situations it might be better to look at your overall design and place these attributes elsewhere.

Lesson 6 Complete

In this lesson we looked at multithreading and how attributes in the different scopes are affected.

What's Next?

In the next lesson we look at redirects & request dispatching.

go to home page Homepage go to top of page Top