Java.Servlet.Should I worry about multithreaded safety when working with servlets?

The short answer is:
👉 Yes, you absolutely should worry about thread safety when working with servlets.

Let’s break this down very clearly:


🧠 Why?

  • In a servlet container (like Tomcat, Jetty, etc.),
    only one instance of your servlet class is created by default.
  • Many threads (one per incoming request) are sent to the same servlet instance to handle requests at the same time.
  • This means multiple threads can execute your doGet(), doPost(), etc. simultaneously!

If you have shared mutable state in your servlet (like instance variables),
you risk:

  • Race conditions
  • Inconsistent data
  • Deadlocks
  • Security issues

🎯 Very Important:

Servlet ObjectShared between Threads?Thread Safe?
Servlet instance✅ Yes (one instance for all threads)❌ No (you must protect shared data)
HttpServletRequest❌ No (each thread gets its own request)✅ Yes (no need to protect)
HttpServletResponse❌ No (each thread gets its own response)✅ Yes (no need to protect)

Request and Response objects are thread-safe (separate for each request).
Servlet instance fields are shared (dangerous if modified).


🛠️ Bad Example (NOT thread-safe!)

public class UnsafeServlet extends HttpServlet {
    private int counter = 0; // SHARED mutable field!

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        counter++;  // NOT thread-safe!
        resp.getWriter().println("Counter: " + counter);
    }
}

Problem:

  • Two users might increase counter at the same time, causing wrong values (lost updates).

✅ Correct Approaches

1. Avoid using instance variables

Simply use only local variables inside doGet(), doPost():

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    int counter = 0; // local to this request
    counter++;
    resp.getWriter().println("Counter: " + counter);
}

2. Use thread-safe objects (if you must share state)

  • Use AtomicInteger, ConcurrentHashMap, etc.
private AtomicInteger counter = new AtomicInteger(0);

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    int currentCount = counter.incrementAndGet();
    resp.getWriter().println("Counter: " + currentCount);
}

AtomicInteger safely increments across threads without race conditions.

3. Synchronize carefully (but try to avoid it)

You can synchronize manually:

private int counter = 0;

@Override
protected synchronized void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    counter++;
    resp.getWriter().println("Counter: " + counter);
}

But beware:

  • Synchronization can cause performance bottlenecks under heavy load.
  • Better to design without shared mutable state whenever possible.

🛡️ Practical Rule of Thumb:

QuestionBest Practice
Do you need to store data per request?✅ Use local variables.
Do you need to share data across users?✅ Use thread-safe collections / atomic variables / application scope (carefully).
Do you need locks?❌ Only if absolutely necessary, otherwise redesign.

🔥 Real-Life Examples of Servlet Thread Safety Issues:

  • Incorrect login counters
  • Random failures in shopping carts
  • Inconsistent session management
  • Mixed-up responses between users

Almost always caused by improperly handled shared variables inside servlets.


🛠️ Quick Recap

AspectServlet Behavior
Servlet instance per app?✅ Yes, only one
Multiple threads per servlet?✅ Yes
Safe to use instance fields?❌ No, unless they are thread-safe
Local variables inside doGet()?✅ Yes, perfectly safe
Use Atomic*, Concurrent* types for shared data?✅ Yes, best practice
This entry was posted in Без рубрики. Bookmark the permalink.