[JAVA] Nous avons rassemblé différentes méthodes d'implémentation de singleton.

Type d'implémentation Singleton

Typique

La manière la plus courante de l'écrire est 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);

ID différent


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

synchronized Ajoutez synchronized au style d'écriture typique pour le rendre Thread Safe. Cependant, il existe un problème de performances car le verrou synchronisé ne peut pas être libéré même après la création de l'instance.

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 En ajoutant à nouveau Check au-dessus de synchronized, Cela évite le "verrouillage synchronisé".

Cependant, en raison de problèmes d'atomicité, ce n'est pas Thread Safe! Je ne connais pas les détails, mais c'est parce que new Singleton3 () est décomposé en plusieurs parties et exécuté.

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() {
        //Non thread-safe en raison de l'atomicité
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }
        return singleton;
    }
}

volatile + DCL Il utilise «volatile», garantit la primitivité et implémente 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() {
        //Volatile garantit l'atomicité
        if (singleton == null) {
            synchronized (Singleton4.class) {
                if (singleton == null) {
                    singleton = new Singleton4();
                }
            }
        }

        return singleton;
    }
}

static fianl Grâce au chargeur de classe, il est Thread Safe et simple à écrire. Cependant, les ressources peuvent être gaspillées.

static_final


public class Singleton5 {

    private static final Singleton5 singleton = new Singleton5();

    private Singleton5() {}

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

Holder C'est une implémentation qui rend Thread Safe avec static final, mais ne gaspille pas de ressources en générant des retards.

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 Utilisez enum. Cependant, les ressources peuvent être gaspillées.

enum


public enum Singleton7 {
    SINGLETON;
}

L'essence n'est pas très différente de «statique final», mais elle est publique. public static final Singleton7 SINGLETON = new Singleton7();

Résumé

Méthode de mise en œuvre Ressources gaspillées Fil sûr Prise en compte des performances des threads
Typique 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

Dans l'ensemble, «volatile + DCL» ou «Holder» est le meilleur!

Recommended Posts

Nous avons rassemblé différentes méthodes d'implémentation de singleton.
Diverses méthodes de la classe Java String
Diverses méthodes de la classe String
Implémentation de la fonction de suppression (si vous avez une clé étrangère)
Nous avons extrait les meilleurs plastiques de Dockerfile!