ProgrammierungJava Backend-Entwickler

Wie implementiert man das Singleton-Muster in Java unter Berücksichtigung von Multithreading und Serialisierung? Welche Umsetzungshinweise gibt es?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

Das klassische Singleton garantiert die Erstellung nur einer Instanz eines Objekts. In Java gibt es mehrere Möglichkeiten der Implementierung, aber unter Berücksichtigung von Multithreading und Serialisierung müssen folgende Punkte beachtet werden:

  1. Thread-sichere Implementierung (Double-checked Locking): Wird häufig für die faule Initialisierung verwendet.
public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
  1. Enum Singleton: Die beste Methode in Bezug auf Schutz vor Serialisierung, Reflection und Multithreading.
enum EnumSingleton { INSTANCE; // Methoden }
  1. Probleme mit der Serialisierung: Ein gewöhnliches Singleton kann nach der Serialisierung/Desserialisierung die Einzigartigkeit seiner Instanz verlieren. Damit es korrekt funktioniert, muss die Methode readResolve() hinzugefügt werden:
private Object readResolve() { return getInstance(); }

Fangfrage

Reicht es aus, die Methode getInstance() synchronisiert zu gestalten, um ein thread-sicheres Singleton zu erreichen?

Antwort: Ja, aber dieser Ansatz führt zu einer Verringerung der Leistung, da synchronized bei jedem Zugriff auf getInstance aufgerufen wird. Effizienter ist das Double-checked Locking in Kombination mit volatile für die Instanz oder die Verwendung eines Enums zur Implementierung des Singletons.

Beispiel für ineffizienten Code:

public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }

Geschichte

Im Finanzsystem wurde bei der Implementierung des Singletons das volatile-Keyword bei der Instanzreferenz in der Double-checked Locking-Implementierung vergessen. Infolgedessen entstanden bei hohen Lasten zufällige Fälle von zwei Instanzen der Klasse, was zu Inkonsistenzen in den Berichten führte.


Geschichte

In der Logging-Bibliothek wurde das Singleton über ein privates statisches Objekt implementiert, jedoch traten bei der Serialisierung und anschließenden Deserialisierung (z.B. in einer Cluster-Umgebung) mehrere Instanzen auf. Das Problem wurde durch die Hinzufügung von readResolve() gelöst.


Geschichte

In der Analysesystem hat der Entwickler ein thread-sicheres Singleton über die synchronisierte Methode getInstance() implementiert. In einem hochbelasteten System kam es während eines Spitzenlastzeitraums zu einem plötzlichen Leistungsabfall, und es stellte sich heraus, dass die Aufrufe von getInstance() (Tausende pro Sekunde) sich gegenseitig blockierten aufgrund unnötiger Synchronisation, obwohl die Initialisierung nur einmal nötig war.