[JAVA] Wir haben verschiedene Implementierungsmethoden von Singleton gesammelt.

Singleton-Implementierungstyp

Typisch

Die typischste Art, es zu schreiben, ist Non Thread Safe.

public class Singleton1 {
    private static Singleton1 singleton = null;

    private Singleton1() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton1 getInstance() {
        if (singleton == null) {
            singleton = new Singleton1();
        }
        return singleton;
    }
}

Non-Thread-Safe


ExecutorService executor = Executors.newFixedThreadPool(2);

Future<Singleton1> f1 = executor.submit(Singleton1::getInstance);
Future<Singleton1> f2 = executor.submit(Singleton1::getInstance);

Singleton1 s1 = f1.get();
Singleton1 s2 = f2.get();

System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);

Unterschiedliche ID


design.singleton.Singleton1@7ba4f24f
design.singleton.Singleton1@3b9a45b3
false

synchronized Fügen Sie dem typischen Schreibstil "synchronisiert" hinzu, um ihn "threadsicher" zu machen. Es gibt jedoch Leistungsprobleme, da die synchronisierte Sperre auch nach dem Erstellen der Instanz nicht aufgehoben werden kann.

synchronized


public class Singleton2 {
    private static Singleton2 singleton = null;

    private Singleton2() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized Singleton2 getInstance() {
        if (singleton == null) {
            singleton = new Singleton2();
        }
        return singleton;
    }
}

Double Check Lock Durch Hinzufügen von Check erneut über "synchronisiert", Es vermeidet die "synchronisierte Sperre".

Aufgrund von Atomproblemen ist es jedoch nicht threadsicher! Ich kenne die Details nicht, aber es liegt daran, dass "new Singleton3 ()" in mehrere Teile zerlegt und ausgeführt wird.

DCL


public class Singleton3 {
    private static Singleton3 singleton = null;

    private Singleton3() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton3 getInstance() {
        //Aufgrund der Atomizität nicht fadensicher
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }
        return singleton;
    }
}

volatile + DCL Es verwendet "flüchtig", garantiert Primitivität und implementiert Double Check Lock.

volatile


public class Singleton4 {
    private static volatile Singleton4 singleton = null;

    private Singleton4() {
        try {
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static Singleton4 getInstance() {
        //Flüchtig garantiert Atomizität
        if (singleton == null) {
            synchronized (Singleton4.class) {
                if (singleton == null) {
                    singleton = new Singleton4();
                }
            }
        }

        return singleton;
    }
}

static fianl Dank des Klassenladeprogramms wird es threadsicher und einfach zu schreiben. Ressourcen können jedoch verschwendet werden.

static_final


public class Singleton5 {

    private static final Singleton5 singleton = new Singleton5();

    private Singleton5() {}

    public static Singleton5 getInstance() {
        return singleton;
    }
}

Holder Es ist eine Implementierung, die Thread Safe mit "static final" macht, aber keine Ressourcen verschwendet, indem Verzögerungen erzeugt werden.

Holder


public class Singleton6 {

    private static class SingletonHolder {
        private static final Singleton6 singleton = new Singleton6();
        private SingletonHolder() { }
    }

    private Singleton6() {
    }

    public static Singleton6 getInstance() {
        return SingletonHolder.singleton;
    }
}

enum Verwenden Sie enum. Ressourcen können jedoch verschwendet werden.

enum


public enum Singleton7 {
    SINGLETON;
}

Die Essenz unterscheidet sich nicht wesentlich von "statischem Finale", ist aber öffentlich. public static final Singleton7 SINGLETON = new Singleton7();

Zusammenfassung

Implementierungsmethode Verschwendete Ressourcen Gewindesicher Berücksichtigung der Thread-Leistung
Typisch NO NO -
synchronized NO YES NO
Double Check Lock NO NO -
volatile + DCL NO YES YES
static fianl YES YES YES
Holder NO YES YES
enum YES YES YES

Insgesamt ist volatile + DCL oder Holder das Beste!

Recommended Posts

Wir haben verschiedene Implementierungsmethoden von Singleton gesammelt.
Verschiedene Methoden der Java String Klasse
Verschiedene Methoden der String-Klasse
Implementierung der Löschfunktion (wenn Sie einen fremden Schlüssel haben)
Wir haben die besten Kunststoffe von Dockerfile extrahiert!