Historycznie, leniwa inicjalizacja pojawiła się w celu optymalizacji wykorzystania zasobów, gdy obiekt jest tworzony tylko wtedy, kiedy jest naprawdę potrzebny. Początkowo było to ważne przy pracy z ciężkimi obiektami, połączeniami, pamięciami podręcznymi (cache) lub w realizacji złożonych wzorców (na przykład Singleton).
Problem – jeśli tworzymy wszystkie zasoby od razu, możemy stracić niepotrzebną pamięć, czas i moc nawet wtedy, gdy obiekt nie jest potrzebny. Lena inicjalizacja rozwiązuje problem „odłożonego” tworzenia.
Rozwiązanie zwykle realizowane jest przez sprawdzenie: jeśli obiekt nie został jeszcze utworzony, tworzymy go, w przeciwnym razie zwracamy istniejący.
Przykład kodu:
public class LazyHolder { private Resource resource; public Resource getResource() { if (resource == null) { resource = new Resource(); } return resource; } }
W warunkach wielowątkowych konieczna jest synchronizacja.
Kluczowe cechy:
Czy Double-Checked Locking jest niezawodną implementacją dla leniwej inicjalizacji Singleton?
Tylko od Java 5, ponieważ wcześniej model pamięci tego nie gwarantował. Należy użyć słowa kluczowego volatile dla pola zasobu.
private volatile Resource resource; public Resource getResource() { if (resource == null) { synchronized(this) { if (resource == null) { resource = new Resource(); } } } return resource; }
Czy ma sens robić leniwą inicjalizację dla lekkich obiektów?
Zwykle nie. Lepiej jest tworzyć "lekkie" obiekty od razu, aby nie skracać czytelności kodu i nie komplikować go zbędną logiką.
Czy leniwa inicjalizacja działa przy serializacji obiektów?
Nie zawsze. Przy serializacji może zostać przywrócony "stary" stan lub wymagana jest dodatkowa logika w readObject().
W usłudze o wysokim obciążeniu specjalny pul obiektów był ładowany leniwie, ale nie był synchronizowany. Dwa wątki jednocześnie inicjalizowały obiekt, prowadząc do wycieków pamięci i nieprzewidywalnych błędów.
Zalety:
Wady:
W dużym web-aplikacji analiza jest realizowana tylko przez wywołanie API za pomocą leniwie inicjalizowanego obiektu proxy z podwójnym sprawdzeniem blokady.
Zalety:
Wady: