How do servlets work? Instantiation, sessions, shared variables and multithreading

Introduction

Servlets are server-side Java components that are used to create dynamic web applications. They work by intercepting and processing client requests and generating responses. In this article, we will explore how servlets work in terms of instantiation, sessions, shared variables, and multithreading.

Instantiation of Servlets

When a client sends a request to a servlet, the servlet container (e.g., Apache Tomcat) checks if an instance of the servlet exists. If it does, the container reuses that instance to handle the request. If not, it creates a new instance of the servlet.

The servlet container typically maintains a pool of servlet instances to handle multiple concurrent requests. The size of this pool can be configured in the server configuration.

Shared Variables and Multithreading

Servlets are inherently multithreaded, meaning that multiple threads can access the same servlet instance simultaneously. This is because servlet containers use a pooling mechanism to manage servlet instances and optimize resource usage.

When multiple requests are received, the servlet container assigns a thread from its pool to each request. These threads then execute the corresponding servlet's service method concurrently. Therefore, it is important to ensure thread safety when using shared variables in servlets.

In order to make the servlet thread-safe, it is recommended to implement proper synchronization mechanisms, such as using synchronized blocks or using concurrent data structures provided by Java, like ConcurrentHashMap or Atomic variables.

Let's take a look at an example:

// Servlet code
public class MyServlet extends HttpServlet {
    private int counter = 0; // shared variable
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        synchronized(this) {
            counter++;
        }
        // rest of the code
    }
}

In the example above, we have a counter variable that is accessed and modified by multiple threads. We use the synchronized keyword to ensure that only one thread can access the counter at a time, preventing any race conditions or inconsistent state.

Sessions and Session Variables

HTTP is a stateless protocol, meaning it does not maintain any information about past requests. However, web applications often require maintaining state information for a user across multiple requests. This is where sessions and session variables come into play.

A session is a way to store and retrieve information about a user's interaction with a web application across multiple requests. Each user is assigned a unique session ID, which is typically stored as a cookie in the client's browser. This session ID is used to associate subsequent requests from the same user with their session data.

Session variables, also known as session attributes, are used to store data that needs to persist across multiple requests for a particular user. Each user has their own set of session variables, which are not shared with other users.

The servlet container manages the creation and maintenance of sessions. When a client sends a request, the servlet container checks if a session already exists for that client. If it does, the container retrieves the session object and makes it available to the servlet. If not, a new session is created and associated with the client.

Let's consider an example:

// Servlet code
public class MyServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        session.setAttribute("username", "John");
        // rest of the code
    }
}

In the example above, we create a session object using the getSession() method in the HttpServletRequest class. We then use the setAttribute() method to store a session variable named "username" with a value of "John". This session variable will be associated with the user's session and can be accessed in subsequent requests.

It is important to note that session variables should be used judiciously, as they consume server memory and can impact the performance of the application. It is generally recommended to store only essential information in session variables and avoid storing large objects or sensitive data.

Differentiating Between Users

The servlet container is responsible for maintaining the association between a session and the user making the request. It uses various mechanisms to differentiate between users:

  • Session ID in the request: The client's browser sends the session ID as a cookie in the request headers. The servlet container extracts this session ID and uses it to retrieve the appropriate session object.
  • URL rewriting: If a client's browser does not support cookies or if cookies are disabled, the servlet container may append the session ID as a query parameter in the URL. This allows the container to maintain the association between the session and the user.

By using these mechanisms, the servlet container is able to differentiate between different users and associate their sessions with the appropriate requests.

Conclusion

In this article, we explored how servlets work in terms of instantiation, sessions, shared variables, and multithreading. We learned that servlets are instantiated by the servlet container and can be shared among multiple users through a pooling mechanism. We also discussed the importance of ensuring thread safety when using shared variables in servlets, as well as the concept of sessions and session variables for maintaining user state. Finally, we looked at how the servlet container differentiates between users using session IDs and URL rewriting.