«Synchronized» in Java: Was es ist und wie es anhand von Beispielen funktioniert

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

«Was bedeutet synchronized?» – eine Frage, die jeden zweiten Junior quält

\n\n

Wenn Sie jemals eine nebenläufige Anwendung in Java geschrieben haben, sind Sie sicherlich auf folgende Situation gestoßen: Zwei Threads ändern gleichzeitig eine Variable, und das Ergebnis sind Bugs, die sich nur einmal in hundert Läufen reproduzieren lassen. Kommt Ihnen bekannt vor? Genau dafür gibt es das Schlüsselwort synchronized. Aber was macht es eigentlich? Wie funktioniert es «unter der Haube»? Und vor allem – wann sollte man es verwenden und wann besser darauf verzichten?

\n\n

In diesem Artikel wiederholen wir nicht einfach die Dokumentation. Wir analysieren eine beliebte Frage von Stack Overflow (diejenige, die tausende Aufrufe gesammelt hat), passen sie an ein Bildungsformat an und zeigen einen Vergleich der Ansätze: Synchronisation auf Methodenebene, auf Blockebene und Alternativen aus java.util.concurrent. Los geht's!

\n\n

Das Problem: Wettlaufsituation (Race Condition)

\n\n

Stellen Sie sich vor: Sie haben einen Zähler, der von zwei Threads inkrementiert wird. Der Code ist einfach, aber das Ergebnis ist unerwartet.

\n\n
public class Counter {\n    private int count = 0;\n\n    public void increment() {\n        count++;\n    }\n\n    public int getCount() {\n        return count;\n    }\n}
\n\n

Wir starten zwei Threads, jeder führt 1000 Inkremente durch. Man würde 2000 erwarten. In Wirklichkeit sind es aber 1987, 1993 oder sogar 1765. Warum? Weil die Operation count++ nicht atomar ist. Sie besteht aus drei Schritten: Lesen → Erhöhen → Schreiben. Die Threads «überschneiden» sich, und eine Änderung geht verloren.

\n\n

Das ist eine race condition – eine Wettlaufsituation. Und synchronized ist eines der wichtigsten Werkzeuge, um dagegen vorzugehen.

\n\n

Was macht synchronized? Ein Blick unter die Haube

\n\n

Das Schlüsselwort synchronized in Java garantiert gegenseitigen Ausschluss (Mutex) und Sichtbarkeit von Änderungen zwischen Threads. Wenn ein Thread in einen synchronized-Block eintritt, erfasst er den Monitor des Objekts (oder der Klasse). Andere Threads, die versuchen, in einen synchronized-Block mit demselben Monitor einzutreten, werden blockiert, bis er freigegeben wird.

\n\n

Wichtig: synchronized funktioniert nur mit einem Monitor. Wenn Sie zwei verschiedene Objekte haben, funktioniert die Synchronisation nicht.

\n\n

Zwei Ebenen der Synchronisation

\n
    \n
  • Synchronisierte Methode – blockiert die gesamte Methode, verwendet den Monitor des Objekts (this).
  • \n
  • Synchronisierter Block – blockiert nur einen Teil des Codes, Sie können jedes Objekt als Monitor angeben.
  • \n
\n\n

Vergleichen wir sie in der Praxis.

\n\n

Vergleich der Ansätze: Methode vs. Block

\n\n

1. Synchronisierte Methode

\n\n

Der einfachste Weg ist, synchronized zur Methodensignatur hinzuzufügen.

\n\n
public class SafeCounter {\n    private int count = 0;\n\n    public synchronized void increment() {\n        count++;\n    }\n\n    public synchronized int getCount() {\n        return count;\n    }\n}
\n\n

Vorteile:

\n
    \n
  • Minimaler Code, leicht lesbar.
  • \n
  • Garantiert, dass die gesamte Methode ein atomarer Vorgang ist.
  • \n
\n\n

Nachteile:

\n
    \n
  • «Schwere» Sperre – selbst wenn die Methode nur eine Zeile enthält, wird der Thread für die gesamte Ausführungszeit blockiert.
  • \n
  • Verringert die Leistung, wenn die Methode lange dauert oder häufig aufgerufen wird.
  • \n
  • Nicht flexibel – Sie können nicht nur einen Teil der Logik synchronisieren.
  • \n
\n\n

2. Synchronisierter Block

\n\n

Feinere Kontrolle. Sie entscheiden selbst, welches Objekt als Monitor verwendet wird.

\n\n
public class SafeCounterWithBlock {\n    private int count = 0;\n    private final Object lock = new Object();\n\n    public void increment() {\n        synchronized (lock) {\n            count++;\n        }\n    }\n\n    public int getCount() {\n        synchronized (lock) {\n            return count;\n        }\n    }\n}

Blogs

Buchempfehlungen