Ever wondered how a single servlet handles multiple client requests without crashing or losing data? Understanding servlet instantiation, session management, shared variables, and multithreading isn’t as straightforward as it seems, and a small mistake can lead to big issues. This guide breaks down how servlets work in a way that clears confusion and reveals what every developer must know but often overlooks.
Table of Contents:
What are Servlets in Java?
Servlets are Java programs that handle client requests and generate dynamic responses. They are the key component of Java web applications, which allows the creation of dynamic web pages and management of server-side logic. Servlets use multithreading, where a single servlet instance can handle multiple requests. They also support session management using HttpSession, cookies, and URL, allowing for the handling of multiple requests. Servlets can interact with databases using JDBC (Java Database Connectivity).
Servlets operate within a Servlet Container (e.g., Apache Tomcat, Jetty) that handles their lifecycle. They follow a request-response model, where they receive HTTP requests (e.g., GET, POST) and generate responses in various formats like HTML, JSON, or XML.
Master Java Today - Accelerate Your Future
Enroll Now and Transform Your Future
Working of Servlets in Java
Servlets work by following a life cycle. The life cycle of the servlet has three stages. These are as follows:
- init();
- service();
- destroy();
1. The init() method initializes the servlet and is called when the servlet starts. This method gets invoked once in the entire life cycle of the Servlet, and it does not respond to any of the user’s commands.
Syntax:
public void init() throws ServletException {
//init() method initializing
}
2. The service() method is used to process the request from the client and is called for every request from the client. The doGet() method for GET requests, the doPost() method for the POST, and doPut() method for PUT requests, and the doDelete() method for the DELETE request are invoked as per the request by the client side.
Syntax:
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
}
3. The destroy() method is called once in the lifetime of the servlet’s life cycle by the servlet container. It is used to release resources like database connections.
Syntax:
public void destroy() {
//destroy() method finalizing
}
Instantiation in Servlets
Instantiation is the process of creating an object of a class. In servlets, it is the process of creating a servlet instance by the servlet container, like Apache Tomcat. It is part of the servlet’s life cycle.
1. Loading and Instantiation:
The Servlet Container loads the servlet class into memory and creates an object of it when it’s first requested or during startup.
2. Initialization (init() method):
After the instantiation, the container calls the init() method to do the starting tasks, such as making the database connections. This method does not handle client requests.
3. Request Handling (service() method):
For every client request, the Servlet container creates a new thread and calls the service() method. The service() method determines the type of the HTTP request (GET, POST, DELETE, PUT) and maps it to the correct method (doGet(), doPost(), doDelete(), doPut()).
4. Destruction (destroy() method):
When the servlet is not needed, the servlet container calls the destroy() method, which is used to free up the resources, such as closing the database connections and freeing up memory.
Unlock Your Future in Java
Start Your Java Journey for Free Today
Sessions in Servlets
Session in a servlet helps to maintain the user state while handling multiple requests from the servlet. It mainly uses the HTTP request for maintaining a session. HTTP is a stateless protocol, which means each request and response is independent of others.
Now, let us discuss the stages of session management in servlets.
1. Client Sends a Request
The user accesses the web application through a browser.
2. Server Creates a Session
If the client does not have a session, the server will create a new session object as an HttpSession. A unique session ID is assigned to the client.
3. Session Tracking
The session ID is stored in the client’s cookies or is passed in the URL. The server uses this session ID to identify the client among the multiple requests.
4. Session Data Storage
The application can store user-related data inside the session object in the form of key-value pairs.
5. Session Expiration or Invalidation
The session expires automatically after some time (the default is 30 minutes).
Shared Variables in Servlets
Shared variables are the variables used by multiple users or threads. These variables need to be handled carefully as servlets are multithreaded, i.e., many users can access them at the same time. If they are not handled properly, it can lead to data inconsistency and race conditions. When a client sends an HTTP request, the servlet container gives a thread to handle the request. It may cause errors if it reads more than one thread and changes the shared variables.
To prevent this, you can use thread-safety techniques, such as local variables, synchronization, and atomic variables. Thread-safe objects should be used.
There are three types of shared variables. These are:
1. Local variables
Local variables are the variables declared inside the body of the methods and exist only during the execution of a request. As each thread has its own copy, they are safe from the issues of concurrency.
2. Instance variables
Instance variables are the variables that are declared inside the servlet class, but outside the method. Since a servlet is a single class, these variables are shared by multiple threads. They are used by multiple users at the same time, which can cause race conditions.
3. Static variables
Static variables are the variables that are shared across all the servlet instances and requests, which makes them prone to data inconsistency in a multi-threaded environment.
Multithreading in Servlets: How It Works Behind the Scenes
When a servlet is deployed to a servlet container such as Tomcat or Jetty, the servlet container might initialize only a single instance of the servlet class. It does not mean that it executes the requests single-threaded. Rather, the container executes multiple client requests in multiple threads.
Whenever a new request arrives, the container allocates a new thread (most often a thread within a thread pool) to service the service() method of the servlet. This allows servlet-based web applications to scale and perform well because many clients may be served concurrently without having to wait for other clients to complete.
Example: Multithreading in Action
public class CounterServlet extends HttpServlet {
private int counter = 0; // Shared instance variable
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
counter++; // Race condition!
response.getWriter().println("Counter: " + counter);
}
}
In the above code:
- Several threads have access to the counter variable concurrently.
- Because counter isn’t thread-safe, this may result in incorrect or inconsistent results.
- This depicts the traditional servlet race condition caused by the use of shared instance variables.
Why This Is a Problem
Servlets are not thread-safe. When you use a shared mutable state (such as instance or static variables), you need to synchronize or not share it. You risk:
- Race conditions: Incorrect data because of concurrent updates.
- Deadlocks: When incorrect synchronization is employed.
- Data leaks: Sensitive data might leak between threads.
Best Practices for Thread Safety in Servlets
- Offload state management to session attributes, request attributes, or external storage (such as databases).
- Don’t use instance variables or static variables to keep request-specific data.
- Use local variables within doGet(), doPost(), etc., since these are thread-safe by nature.
- When shared data are required, use synchronization tools or concurrent collections (ConcurrentHashMap, etc.).
What Happens When Two Users Access the Same Servlet at the Same Time
When two users access the same servlet at the same time, the behavior depends on how the servlet is written and whether it is thread-safe or not.
When two users access the same servlet at the same time, the server will create two threads. These threads will run at the same time. If the servlet is not designed to handle multiple requests at the same time, a problem will occur as they can mix the data of different threads.
How do Containers like Tomcat Manage Servlet Threading
Apache Tomcat manages the servlet threading by using the thread-per-request method.
Let us discuss this in detail.
1. One Thread Per User Request
When a user sends a request to a servlet, Tomcat assigns that request to a thread from its internal thread pool. If 10 users send requests at the same time to a servlet, Tomcat will use or allocate 10 threads to handle those requests at the same time.
2. Only One Servlet Object
Tomcat creates only one object of each servlet, but uses multiple threads to handle concurrent requests. All user requests use only this servlet object to process. That’s why the code that is inside the servlet must be kept thread-safe so that no data of the user gets mixed up.
3. Thread Pool
Tomcat uses a pool of threads, i.e., you can set how many threads it can use (maxThreads).
If all the threads are busy working, new requests will wait in a queue.
Top 3 Real Problems Caused by Improper Variable Use in Servlets
1. Data Leakage
Servlets are singletons, i.e., only one instance is created for each servlet, and each servlet class has its own instance. When two users access the same servlet, their data gets mixed up. This happens when instance variables are used to store user-specific data.
2. Race Conditions
A race condition is a condition that occurs when many threads try to read or write a shared variable at the same time.
Servlets process each request in a separate thread, but as all the threads use the same servlet instance, they can interfere with each other.
3. Crash of Application
When shared resources are changed with multiple threads at the same time, they get corrupted or can throw errors, as most of the Java collections are not thread-safe. If one thread is reading while another is writing, it can throw exceptions like the ConcurrentModificationException.
Get 100% Hike!
Master Most in Demand Skills Now!
Conclusion
Servlets are Java programs that handle client requests and generate dynamic responses. The servlet container manages their creation, processing, and removal. Sessions help us to store the user data when it is requested, and the shared variables must be used carefully to avoid errors. Multithreading improves the speed of handling the request, but with that, there can also be some problems that need to be handled carefully.
If you want to learn more about Java, you can refer to our Java Course.
How Do Servlets Work in Java – Instantiation, Sessions, Shared Variables, and Multithreading – FAQs
Q1. How do servlets handle multiple requests concurrently?
Servlets use threads to handle multiple requests at the same time, and for each request.
Q2. Is the servlet multithreaded or single threaded?
Servlets are multithreaded.
Q3. What is the main purpose of a servlet?
To extend the capabilities of servers that host applications accessed using a request-response programming model.
Q4. What is the life cycle of a servlet?
The Life Cycle of a Servlet consists mainly of three methods – init(), service(), and destroy().
Q5. Is servlet an API or not?
Yes, the Java Servlet API is a powerful tool for creating web applications.