Blog

EJAPP Top 10 Countdown: #3 - Falsch implementierte Gleichzeitigkeit

Vincent Partington

Aktualisiert Oktober 23, 2025
3 Minuten

Wir haben jetzt die Top 3 des EJAPP Top 10 Countdowns erreicht, also legen wir los... Falsch implementierte Gleichzeitigkeit kann die Leistung Ihrer Anwendung auf sehr unvorhersehbare Weise beeinträchtigen. Anwendungen, die bei geringer Belastung recht gut funktionieren, können bei höherer Belastung zum Stillstand kommen.Eine Hauptursache ist Sperrkonfliktedie nur dann zu einem Problem werden, wenn mehrere Threads beteiligt sind. Wenn zum Beispiel eine Anfrage, die 100ms dauert, 25ms in einem kritischen Abschnitt verbringt, können nicht mehr als vier Anfragen alle 100ms bearbeitet werden. Ganz gleich, wie sehr Sie die restlichen 75 ms reduzieren, das Amdahlsche Gesetz besagt, dass die maximale Beschleunigung durch die Einführung der Parallelisierung 4 beträgt!

Sperrkonflikte können durch verschiedene Dinge verursacht werden:

  • Synchronisierte Methoden und Blöcke, die sehr lange brauchen, um abgeschlossen zu werden. Siehe EJAPP Top 10 #6 - Unsachgemäßes Caching für ein Beispiel.
  • Lang laufende Datenbanktransaktionen. Diese beeinträchtigen ebenfalls die Leistung, da sie große Mengen an Ressourcen wie Transaktionsprotokolle und Speicher verbrauchen.
  • Lang laufende Datenbanktransaktionen mit hohen Isolationsstufen, die zu einer Eskalation der Sperren führen. Statt nur einer Zeile wird eine ganze Tabelle gesperrt, wodurch die Wahrscheinlichkeit steigt, dass mehrere Threads um dieselbe Sperre konkurrieren.

Während Sperrkonflikte nur dann ein Problem sind, wenn mehrere Threads beteiligt sind, fällt der mit der Verwaltung der Sperre verbundene Overhead auch dann an, wenn nur ein Thread beteiligt ist. Dies ist der Grund, warum Entwickler seit JDK 1.2 ArrayList gegenüber Vector und HashMap gegenüber Hashtable bevorzugen. Genauso wie die Speicherverwaltung immer billiger geworden ist, hat sich die Leistung von Sperren in den letzten JDK-Versionen verbessert. JDK 1.6 enthält beispielsweise eine Reihe von Leistungsverbesserungen bei der Synchronisierung wie Lock Elision, Adaptive Locking und Lock Coarsening. Diese machen StringBuilder schon nach einer einzigen JDK-Version überflüssig!Natürlich kann der Verzicht auf Sperren die Leistung Ihrer Anwendung verbessern, kann aber auch Ihre Anwendung ernsthaft stören! Auch wenn die Gleichzeitigkeit ein kompliziertes Thema ist, müssen sich alle Enterprise Java-Entwickler damit befassen. Es gibt jedoch eine Reihe von einfachen Richtlinien:

  • Minimieren Sie die Menge der Daten, auf die mehrere Threads zugreifen und die sie verändern müssen, und begrenzen Sie so die Anzahl der benötigten Sperren. Dazu gehören statische Variablen, Singletons, Datenbankzeilen usw.
  • Wenn gemeinsam genutzte Daten geändert werden müssen, halten Sie den kritischen Abschnitt so kurz wie möglich.
  • In Java sollten Sie es vermeiden, eigene Synchronisierungsprimitive zu schreiben. Verwenden Sie stattdessen java.util.concurrent (oder backport-util-concurrent).
  • In der Datenbank sollten Sie die Verwendung einer optimistischen Gleichzeitigkeitssteuerung (von manchen verwirrend als optimistisches Sperren bezeichnet, obwohl es eigentlich nicht um Sperren geht) oder die Abschaffung von Transaktionen in Betracht ziehen.
  • Und schließlich sollten Sie sich die Tipps zur Synchronisierungsleistung auf der Java Performance Tuning-Website ansehen.

Vielen Dank an Peter Veentjer für seinen wertvollen Beitrag zu diesem Blog.

Mehr aus dieser Serie

Verfasst von

Vincent Partington

Contact

Let’s discuss how we can support your journey.