ProgrammatieJava backend ontwikkelaar

Hoe implementeer je het Singleton-patroon in Java rekening houdend met multithreading en serialisatie? Welke nuances zijn er bij de implementatie?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

De klassieke Singleton garandeert de creatie van slechts één exemplaar van een object. In Java zijn er verschillende manieren om dit te implementeren, maar met betrekking tot multithreading en serialisatie moet je rekening houden met de nuances:

  1. Thread-safe implementatie (Double-checked Locking): Vaak gebruikt voor lazy initialisatie.
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: De beste manier qua bescherming tegen serialisatie, reflection en multithreading.
enum EnumSingleton { INSTANCE; // methodes }
  1. Problemen met serialisatie: Een gewone Singleton kan na serialisatie/deserialisatie zijn uniciteit verliezen. Voor een correcte werking moet je de methode readResolve() toevoegen:
private Object readResolve() { return getInstance(); }

Misleidende vraag

Is het voldoende om de gesynchroniseerde methode getInstance() te gebruiken voor een thread-safe Singleton?

Antwoord: Ja, maar deze benadering leidt tot verminderde prestaties omdat synchronized bij elke aanroep van getInstance wordt aangeroepen. Double-checked Locking + volatile voor instance of het gebruik van Enum voor de implementatie van Singleton is efficiënter.

Voorbeeld van inefficiële code:

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

Geschiedenis

In een financieel systeem werd vergeten volatile toe te voegen aan de instance-referentie in double-checked locking. Dit leidde op hoge belasting tot willekeurige gevallen van het creëren van twee exemplaren van de klasse, wat resulteerde in inconsistentie in rapportage.


Geschiedenis

In de logboekbibliotheek werd Singleton gerealiseerd via een privé statisch object, maar bij serialisatie en daaropvolgende deserialisatie (bijvoorbeeld in een clusteromgeving) ontstonden er meerdere exemplaren. Het probleem werd opgelost door readResolve() toe te voegen.


Geschiedenis

In een analytisch systeem implementeerde een ontwikkelaar een thread-safe Singleton via de gesynchroniseerde methode getInstance(). In een systeem met hoge belasting ontstond er een scherpe daling van de prestaties op het hoogtepunt; het bleek dat de aanroepen van getInstance() (duizenden keren per seconde) elkaar blokkeerden vanwege onnodige synchronisatie, hoewel initialisatie slechts één keer nodig was.