Współbieżność - blokada na obiecie Class?

0

Witam

Zapoznaję się ze wzorcem projektowym Singleton. Natrafiłem w internecie na przykładową implementację:

public static SingletonSimpleLazy getInstance() {
    if (instance == null) {
        synchronized (SingletonSimpleLazy.class) {
            if (instance == null) {
                instance = new SingletonSimpleLazy();
            }
        }
    }
    return instance;
}

Czy efekt w działaniu będzie inny jeżeli użyjemy ** this** zamiast Class?

1

Tak, efekt będzie inny ;) W statycznej metodzie nie możesz odwołać się do this.

0

Rozumiem. A gdyby pobyć się static, to nadal efekt byłby identyczny z użyciem this?

1

Gdybyś pozbył się static, to żeby wywołać metodę musiałbyś skonstruować instancję obiektu. Dodatkowo każda taka instancja synchronizowałaby dostęp do metody w oparciu o własny monitor. W efekcie nie miałbyś singletona i nie miałbyś synchronizacji.

0

Racja, teraz rozumiem, dzięki :) A możesz mi jeszcze wytłumaczyć dlaczego poniższa implementacja jest bezpieczna wątkowo?

public class SingletonStaticHolder {

    private SingletonStaticHolder() {
    }

    private static class Holder {
        private static final SingletonStaticHolder INSTANCE = new SingletonStaticHolder();
    }

    public static SingletonStaticHolder getInstance() {
        return Holder.INSTANCE;
    }
}

Załóżmy, że dwa wątki równocześnie wywołują metodę getInstance(). Ponieważ klasa Holder nie została jak dotąd użyta następuje jej ładowanie a przy okazji inicjalizacja INSTANCE. Czy drugi wątek również może wykonać w tym samym czasie ładowanie klasy? Spodziewam się, że nie rozumiem dlaczego...

0

wydaje mi się, że ta implementacja jest bezpieczna wątkowo, ponieważ zawiera jedną linijkę kodu - jedną akcję. Czyli jak metoda zostanie wywołana w wątku to od razu zwróci wartość, zamiast zapisania stanu i zmiany contextu.

Inaczej mówiąc, nie ma możliwości, żeby kilka wątków równolegle wykonywało tą metodę


Poniżej jest chyba bardziej poprawna odpowiedź :P

0

Jest bezpieczna bo ładowaniue statycznych klas/instancji odbywa się podczas "inicjalizacji JVM" i już na tym etapie tworzona jest instancja singletona.

0
Kubańczyk napisał(a):

wydaje mi się, że ta implementacja jest bezpieczna wątkowo, ponieważ zawiera jedną linijkę kodu - jedną akcję. Czyli jak metoda zostanie wywołana w wątku to od razu zwróci wartość, zamiast zapisania stanu i zmiany contextu.

Inaczej mówiąc, nie ma możliwości, żeby kilka wątków równolegle wykonywało tą metodę

Nie ma żadnego sensu to co mówisz. Jest to bezpiecznie bo
1)Jest static a więc inicjacja na ładowaniu
2)Jest final

0
Jan Ko napisał(a):

Jest bezpieczna bo ładowaniue statycznych klas/instancji odbywa się podczas "inicjalizacji JVM" i już na tym etapie tworzona jest instancja singletona.

No tak, bo w sumie maszyna wirtualna ładuje klasę, tak? Wątek tylko iniciuje to ładowanie odwołując się do getInstance().

0
Jan Ko napisał(a):

Jest bezpieczna bo ładowaniue statycznych klas/instancji odbywa się podczas "inicjalizacji JVM" i już na tym etapie tworzona jest instancja singletona.

No tak, bo w sumie maszyna wirtualna ładuje klasę, tak? Wątek tylko iniciuje to ładowanie odwołując się do getInstance().

3
Jan Ko napisał(a):

Jest bezpieczna bo ładowaniue statycznych klas/instancji odbywa się podczas "inicjalizacji JVM" i już na tym etapie tworzona jest instancja singletona.

Nie. Ładowanie klas odbywa się podczas ich pierwszego użycia. Możesz sobie printlna wstawić w konstruktor klasy i sprawdzić kiedy się wywołuje. Dopóki jej nie ruszysz to nic się nie załaduje.

W normalnej aplikacji nawet jeśli masz 5 gigabajtów JARów na classpathu, a używasz tylko 100 megabajtów klas to tylko 100 megabajtów klas zostanie załadowanych. Jeżeli natomiast używasz jakichś skanerów classpatha np ze Springa to wszystko się może zdarzyć i możliwe, że Spring niepotrzebnie załaduje te 5 gigabajtów klas do pamięci. Chociaż z drugiej strony można analizować klasy bez ich ładowania, więc być może Spring ma jakiś dekoder plików .class, który nie używa ClassLoaderów.

Kuben napisał(a):

Racja, teraz rozumiem, dzięki :) A możesz mi jeszcze wytłumaczyć dlaczego poniższa implementacja jest bezpieczna wątkowo?

public class SingletonStaticHolder {

    private SingletonStaticHolder() {
    }

    private static class Holder {
        private static final SingletonStaticHolder INSTANCE = new SingletonStaticHolder();
    }

    public static SingletonStaticHolder getInstance() {
        return Holder.INSTANCE;
    }
}

Załóżmy, że dwa wątki równocześnie wywołują metodę getInstance(). Ponieważ klasa Holder nie została jak dotąd użyta następuje jej ładowanie a przy okazji inicjalizacja INSTANCE. Czy drugi wątek również może wykonać w tym samym czasie ładowanie klasy? Spodziewam się, że nie rozumiem dlaczego...

Ładowanie klas w JVMie jest bezpieczne wątkowo.

https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html#loadClass-java.lang.String-boolean-

Unless overridden, this method synchronizes on the result of getClassLoadingLock method during the entire class loading process.

0

Do tego co napisał @Wibowit masz jeszcze uzupełnienie łopatologiczne -> https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom

1 użytkowników online, w tym zalogowanych: 0, gości: 1