🧵 Servlets Are Multithreaded by Default
When multiple clients send requests to the same servlet, the servlet container creates a new thread for each request, but only one instance of the servlet is created and shared across threads.
⚠️ This means:
If your servlet has shared mutable state, you can run into race conditions, data corruption, and thread-safety issues.
🛑 Example of a Thread Safety Issue
public class CounterServlet extends HttpServlet {
private int counter = 0;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
counter++; // 💣 Race condition!
res.getWriter().write("Counter: " + counter);
}
}
This servlet is not thread-safe. Multiple requests can corrupt the counter
variable.
✅ How to Make It Thread-Safe
1. Use Local Variables (Preferred)
Local variables are stored on the thread’s stack, so each thread gets its own copy.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
int localCounter = 0;
localCounter++; // Safe
res.getWriter().write("Local Counter: " + localCounter);
}
2. Synchronize Access
If you must use shared state, synchronize access:
private int counter = 0;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
synchronized (this) {
counter++;
res.getWriter().write("Counter: " + counter);
}
}
But this can lead to bottlenecks — only one thread at a time enters the block.
3. Use Concurrent Utilities
Java gives you thread-safe classes out of the box:
private final AtomicInteger counter = new AtomicInteger();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
int current = counter.incrementAndGet();
res.getWriter().write("Counter: " + current);
}
Or use:
ConcurrentHashMap
CopyOnWriteArrayList
ReentrantLock
(more control thansynchronized
)ThreadLocal
(for per-thread data)
🔒 Servlet Container Itself Ensures:
- Each request runs in its own thread
- Only one servlet instance per declaration
- ServletContext and ServletConfig are shared objects — be careful!
❌ Not Thread-Safe by Default:
- Instance variables in servlets
- Shared objects like lists or maps without synchronization
✅ Thread-Safe by Default:
- Local variables inside
doGet()
/doPost()
- Immutable objects (
String
,Integer
, etc.) ThreadLocal
for per-request storage
🧠 Summary
Feature | Thread-Safe? | Notes |
---|---|---|
Local variables | ✅ | Best choice |
Instance variables (mutable) | ❌ | Use synchronized or Atomic types |
ServletContext , HttpSession | ❌ | Be careful when storing mutable data |
Java concurrent utils | ✅ | Use Atomic* , ConcurrentHashMap , etc. |
ThreadLocal | ✅ | Great for request-specific data |