Lusta tartó

A lusta tartó a számítógép-programozásban egy lusta betöltésű egyke programtervezési minta. A Java minden verziója szálbiztosan valósítja meg a lusta inicializációt. Ennek az a feltétele, hogy a példányt ne lehessen elérni a csomagon kívül. A duplán ellenőrzött zárolást a Java 1.5 előtti verziók nem biztosították.[1]

public class Something {
    private Something() {}

    private static class LazyHolder {
        static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

A megvalósítás az inicializáció szakaszára hagyatkozik, amit a Java specifikációja (JLS) is előír. Ha a virtuális gép betölti a Something osztályt, akkor inicializálnia kell. Mivel nincsenek osztályváltozók, az inicializáció triviális. A LazyHolder osztály szintű osztálydefiníció mindaddig nem inicializálódik, amíg nem kell végrehajtani. Ehhez meg kell hívni a Something osztály getInstance metódusát. A LazyHolder inicializációjának eredménye az INSTANCE osztályváltozó, amit a külső osztály privát konstruktora inicializál. Mivel az osztály inicializációja a Java specifikációja szerint szekvenciális, nincs szükség további szinkronizációra. És mivel az inicializációs szakasz szekvenciális műveletben írja az INSTANCE változót, a getInstance minden konkurrens hívása ugyanazt a korrektül inicializált INSTANCE példányt adja vissza minden szinkronizációs adminisztráció nélkül.

A minta előnye, hogy hatékony és szálbiztos egykét nyújt szinkronizáció nélkül, és hatékonyabb, mint a megvárakoztató szinkronizáció. Nem alkalmas arra, hogy olyan osztályt inicializáljon, amiből több példányra lenne szükség.

Alkalmazásakor biztosítani kell, hogy a Something konstrukciója garantáltan sikeres legyen. Ugyanis ha a JVM nem tudja inicializálni az osztályt, akkor a betöltő NoClassDefFoundError hibával leáll.

Példa:

public class PughFail {
    public static class Something {
        private Something() {
            super();
            System.out.println(this.getClass().getName() + " called");
            if (System.currentTimeMillis() > 0) {
                System.out.println("EMULATING INIT FAILURE");
                throw new RuntimeException("EMULATING INIT FAILURE");
            }
        }
        private static class LazyHolder {
            private static final Something INSTANCE = new Something();
        }
        public static Something getInstance() {
            return LazyHolder.INSTANCE;
        }
    }
    public static void main(String[] args) {
        System.out.println("First try");
        try {
            Something.getInstance();
        } catch (Throwable t) {
            System.out.println(t);
        }
        System.out.println("Second try");
        try {
            Something.getInstance();
        } catch (Throwable t) {
            System.out.println(t);
        }
    }
}

Eredmény:

First try
PughFail$Something called
EMULATING INIT FAILURE
java.lang.ExceptionInInitializerError
Second try
java.lang.NoClassDefFoundError: Could not initialize class PughFail$Something$LazyHolder

Források

[szerkesztés]

Jegyzetek

[szerkesztés]

Fordítás

[szerkesztés]

Ez a szócikk részben vagy egészben az Initialization-on-demand holder idiom című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként. Ez a szócikk részben vagy egészben az Initialization-on-demand holder idiom című német Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.