Servlets in Java: Instanzen, Sessions und Multithreading – eine detaillierte Analyse

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum Servlets immer noch Angst machen – und wie man damit lebt?

\n\n

Wenn Sie jemals auf Stack Overflow nach einer Antwort auf die Frage „Wie funktionieren Servlets?“ gesucht haben, sind Sie sicherlich auf den legendären Thread mit tausenden von Aufrufen gestoßen. Die Frage, die dort immer wieder gestellt wird: „Wie viele Instanzen eines Servlets werden erstellt? Wie teile ich Daten zwischen Anfragen? Und warum verhält sich meine Variable wie verrückt?“

\n\n

Seien wir ehrlich: Servlets sind keine Rocket Science, aber es gibt genügend Fallstricke. Besonders wenn es um Multithreading und gemeinsame Variablen geht. In diesem Artikel wiederholen wir nicht einfach die Dokumentation. Wir nehmen ein reales Beispiel aus der Praxis, zerlegen es in seine Bestandteile und zeigen, wie man Fehler vermeidet. Los geht's!

\n\n

Wie gelangt ein Servlet in den Speicher: Instanziierung und Lebenszyklus

\n\n

Beginnen wir mit dem Einfachen: Wie viele Instanzen eines Servlets werden erstellt? Die Antwort: eine. Ja, Sie haben richtig gehört. Der Servlet-Container (Tomcat, Jetty und andere) erstellt genau eine Instanz jedes Servlets für die gesamte Anwendung. Und diese Instanz lebt, bis die Anwendung entladen wird.

\n\n

So sieht ein typischer Lebenszyklus aus:

\n\n
    \n
  • init() – wird einmal beim Laden des Servlets aufgerufen. Hier initialisieren Sie Datenbankverbindungen, Konfigurationen und Ähnliches.
  • \n
  • service() – wird für jede eingehende Anfrage aufgerufen. Hier findet die Verarbeitung statt.
  • \n
  • destroy() – wird vor dem Entladen des Servlets aufgerufen. Hier räumen Sie Ressourcen auf.
  • \n
\n\n

Der entscheidende Punkt: service() (und seine Ableitungen doGet, doPost) wird in einem separaten Thread für jede Anfrage ausgeführt. Das bedeutet, dass dieselbe Servlet-Instanz Hunderte von Anfragen gleichzeitig verarbeitet. Und hier wird es richtig interessant.

\n\n

Beispiel: Ein Servlet, viele Threads

\n\n
@WebServlet("/counter")\npublic class CounterServlet extends HttpServlet {\n    private int counter = 0;  // shared variable!\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) \n            throws ServletException, IOException {\n        counter++;\n        resp.getWriter().write("Counter: " + counter);\n    }\n}
\n\n

Wenn Sie diesen Code ausführen und 10 parallele Anfragen senden, erhalten Sie nicht die Zahlen von 1 bis 10 in der richtigen Reihenfolge. Stattdessen sehen Sie so etwas wie: 2, 5, 3, 8, 1... Oder der counter überspringt möglicherweise Werte. Warum? Weil counter++ keine atomare Operation ist. Zwei Threads können denselben Wert lesen, ihn erhöhen und zurückschreiben, wodurch eine Inkrementierung verloren geht.

\n\n

Fazit: Instanzfelder eines Servlets sind Shared Variables. Sie sind für alle Threads sichtbar. Und wenn Sie den Zugriff nicht synchronisieren, erhalten Sie eine Race Condition.

\n\n

Sessions: Wie man Benutzer nicht verwechselt

\n\n

Stellen Sie sich nun vor: Sie möchten Daten speichern, die für jeden Benutzer eindeutig sind (Warenkorb, Login, Einstellungen). Dafür gibt es in Java Servlets die HttpSession. Eine Session wird für jeden neuen Benutzer erstellt und lebt, bis er den Browser schließt oder das Timeout abläuft.

\n\n

Eine Session ist kein gemeinsamer Speicher. Jeder Benutzer erhält seine eigene Session-Instanz. Innerhalb der Session können Sie jedoch beliebige Objekte speichern, die nur für diesen Benutzer zugänglich sind.

\n\n

Beispiel: Arbeiten mit einer Session

\n\n
@WebServlet("/session-demo")\npublic class SessionServlet extends HttpServlet {\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) \n            throws ServletException, IOException {\n        HttpSession session = req.getSession();\n        Integer visitCount = (Integer) session.getAttribute("visitCount");\n        if (visitCount == null) {\n            visitCount = 0;\n                

Blogs

Buchempfehlungen