🧵 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:
ConcurrentHashMapCopyOnWriteArrayListReentrantLock(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.) ThreadLocalfor 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 |