Modèle de conception - modèle singleton (y compris : style d'homme affamé, style d'homme paresseux, double vérification, classe interne statique, énumération)

 Liens connexes:

Colonne [Design Pattern] : Colonne [Design Pattern]

Des exemples de codes pertinents peuvent être téléchargés :  Exemples de modèles de conception courants en Java

motif singleton

        Singleton Pattern (Singleton Pattern) est l'un des modèles de conception les plus simples de Java. Ce type de modèle de conception est un modèle de création, qui offre un moyen optimal de créer des objets.

        Ce modèle implique une seule classe qui est responsable de la création de ses propres objets tout en s'assurant qu'un seul objet est créé. Cette classe fournit un moyen d'accéder directement à son seul objet, sans instancier un objet de cette classe.

Le soi-disant singleton signifie que le programme entier a et une seule instance . Cette classe est responsable de la création de ses propres objets tout en s'assurant qu'un seul objet est créé. En Java, il est généralement utilisé dans l'implémentation de classes d'outils ou la création d'objets consommateurs de ressources.

        Dans le système informatique, il existe des corbeilles de recyclage Windows, des systèmes de fichiers dans le système d'exploitation, des pools de threads en multithreading, des objets pilotes pour les cartes graphiques, des services de traitement en arrière-plan pour les imprimantes, des objets journaux pour les applications, des pools de connexions pour les bases de données et les connexions aux sites Web. de , les objets de configuration des applications Web, les boîtes de dialogue des applications, les caches du système, etc. sont souvent conçus comme des singletons.

        Le modèle singleton est également largement utilisé dans la vie réelle.Par exemple, le PDG de l'entreprise, le responsable de service, etc. appartiennent tous au modèle singleton. Le ServletContext et le ServletContextConfig dans la norme J2EE, le ApplicationContext dans l'application Spring Framework et le pool de connexions dans la base de données sont également des modèles singleton.

Caractéristiques du modèle singleton

  • Une classe singleton ne peut avoir qu'une seule instance.

  • Une classe singleton doit créer sa propre instance unique.

  • Une classe singleton doit fournir cette instance à tous les autres objets .

Avantages et inconvénients du modèle singleton

avantage:

  • Le mode singleton peut garantir qu'il n'y a qu'une seule instance en mémoire, ce qui réduit la surcharge de mémoire

  • L'occupation multiple des ressources peut être évitée

  • Le mode singleton définit un point d'accès global, qui peut optimiser et partager l'accès aux ressources

défaut:

  • Le mode singleton n'a généralement pas d'interface et est difficile à étendre . Si vous souhaitez développer, il n'y a pas d'autre moyen que de modifier le code d'origine, ce qui viole le principe d'ouverture et de fermeture

  • Dans les tests simultanés, le modèle singleton n'est pas propice au débogage du code. Pendant le processus de débogage, si le code du singleton n'est pas exécuté, un nouvel objet ne peut pas être simulé.

  • Le code fonctionnel du mode singleton est généralement écrit dans une classe. Si la conception fonctionnelle n'est pas raisonnable, il est facile de violer le principe de responsabilité unique.

8 façons du modèle Singleton

  1. Style affamé (constante statique)

  2. Style chinois affamé (bloc de code statique)

  3. Paresseux (non thread-safe)

  4. Paresseux (thread-safe, méthodes synchronisées)

  5. Paresseux (blocs de code synchronisés et sécurisés pour les threads)

  6. revérifier

  7. classe interne statique

  8. énumérer

Style affamé (constante statique)

Exemple d'application de style Hungry (constante statique), les étapes sont les suivantes :

  1. Privatisation des constructeurs (empêcher les nouveaux)

  2. objet créé à l'intérieur de la classe

  3. Exposez une méthode publique statique. comme:getInstance()

  4. Code

avantage

  • L'instanciation est terminée lorsque la classe est chargée, évitant les problèmes de synchronisation des threads

défaut

  • L'effet de chargement différé n'est pas atteint. Si l'instance n'a jamais été utilisée, cela entraînera un gaspillage de mémoire.

exemple de code

Mode singleton : SingletonEHan01.java

public class SingletonEHan01 {

    /**
     * 1. 构造器私有化,外部不能 new
     */
    private SingletonEHan01() {}

    /**
     * 2. 本类内部创建对象实例
     */
    private final static SingletonEHan01 instance = new SingletonEHan01();

    /**
     * 3. 提供公有的静态方法,返回对象实例
     * @return SingletonEHan01
     */
    public static SingletonEHan01 getInstance() {
        return instance;
    }

    /**
     * 4. 代码实现
     */
    public void hello() {
        System.out.println("饿汉式(静态变量):Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 1. 饿汉式(静态变量)
        SingletonEHan01 singletonEHan01 = SingletonEHan01.getInstance();
        singletonEHan01.hello();
    }
}

Style chinois affamé (bloc de code statique)

Exemple d'application de style Hungry (bloc de code statique), les étapes sont les suivantes :

  1. Privatisation des constructeurs (empêcher les nouveaux)

  2. Cette classe définit une variable d'instance statique à l'intérieur et crée un objet d'instance dans le bloc de code statique

  3. Exposez une méthode publique statique. comme:getInstance()

  4. Code

avantage

  • L'instanciation est terminée lorsque la classe est chargée, évitant les problèmes de synchronisation des threads

défaut

  • L'effet de chargement différé n'est pas atteint. Si l'instance n'a jamais été utilisée, cela entraînera un gaspillage de mémoire.

exemple de code

Mode singleton : SingletonEHan02.java

public class SingletonEHan02 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonEHan02() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonEHan02 instance;

    static {
        // 静态代码块中创建实例对象
        instance = new SingletonEHan02();
    }

    /**
     * 3. 提供公有的静态方法,返回对象实例
     * @return SingletonEHan02
     */
    public static SingletonEHan02 getInstance() {
        return instance;
    }

    /**
     * 4. 代码实现
     */
    public void hello() {
        System.out.println("饿汉式(静态代码块):Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 2. 饿汉式(静态代码块)
        SingletonEHan02 singletonEHan02 = SingletonEHan02.getInstance();
        singletonEHan02.hello();
    }
}

Style paresseux (le fil n'est pas sûr, ne peut pas être utilisé dans le développement réel)

Avantages et inconvénients

  1. Il a l'effet du Lazy Loading (chargement paresseux), mais il ne peut être utilisé que sous un seul thread

  2. Si sous multi-threading, un thread entre dans le bloc d'instruction de jugement et qu'un autre thread passe également l'instruction de jugement avant d'avoir le temps de s'exécuter, plusieurs instances seront générées à ce moment. Par conséquent, cette méthode ne peut pas être utilisée dans un environnement multithread if (singleton == null)

en conclusion:

En développement réel, n'utilisez pas cette méthode !

exemple de code

Modèle de singleton : SingletonLanHan01.java

public class SingletonLanHan01 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan01() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan01 instance;

    /** 3. 提供公有的静态方法,当使用到该方法时才去创建 instance */
    public static SingletonLanHan01 getInstance() {
        // 在多线程下,若多个线程都通过了该判断,便会产生多个实例,所以多线程环境下不推荐使用
        if (instance == null) {
            instance = new SingletonLanHan01();
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程不安全):Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 3. 懒汉式(线程不安全,实际开发中不推荐使用)
        SingletonLanHan01 singletonLanHan01 = SingletonLanHan01.getInstance();
        singletonLanHan01.hello();
    }
}

Paresseux (thread-safe, méthodes synchronisées)

Fournit des méthodes publiques statiques et ajoute du code de traitement de synchronisation, c'est-à-dire synchronized des mots clés, qui résout le problème de l'insécurité des threads.

Cependant, cette méthode est trop inefficace et n'est pas recommandée.

exemple de code

Mode singleton : SingletonLanHan02.java

public class SingletonLanHan02 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan02() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan02 instance;

    /**
     * 3. 提供公有的静态方法,加入同步处理代码,解决线程不安全的问题,当使用到该方法时才去创建 instance
     *
     * 注意:正因为加入 synchronized 关键字,则可能导致效率太低,不建议使用
     *
     * */
    public static synchronized SingletonLanHan02 getInstance() {
        if (instance == null) {
            instance = new SingletonLanHan02();
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程安全,同步方法):Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 4. 懒汉式(线程安全,同步方法)
        SingletonLanHan02 singletonLanHan02 = SingletonLanHan02.getInstance();
        singletonLanHan02.hello();
    }
}

Paresseux (blocs de code synchronisés et sécurisés pour les threads)

Avantages et inconvénients

  • Cette méthode est destinée à améliorer la méthode de synchronisation précédente (c'est-à-dire : synchronized) , car l'efficacité de la méthode de synchronisation est trop faible, et elle est modifiée pour produire de manière synchrone des blocs de code instanciés.

  • Cependant, ce type de synchronisation ne peut pas jouer le rôle de synchronisation de thread . Si sous multi-threading, un thread entre dansle bloc d'instruction de jugement et n'a pas eu le temps de l'exécuter à l'avenir, et qu'un autre thread passe également l'instruction de jugement, alors plusieurs des threads seront générés. Par conséquent, cette méthode ne peut pas être utilisée dans un environnement multithread if (singleton == null)

en conclusion:

En développement réel, cette méthode ne peut pas être utilisée !

exemple de code

Mode singleton : SingletonLanHan03.java

public class SingletonLanHan03 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan03() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan03 instance;

    /** 3. 提供公有的静态方法 */
    public static SingletonLanHan03 getInstance() {
        if (instance == null) {
            /**
             * 加入同步处理代码块
             *
             * 值得注意:
             * 在多线程下,若多个线程都通过了 if (instance == null) 判断,因此便还是会产生多个实例,所以多线程环境下不推荐使用
             */
            synchronized(SingletonLanHan03.class) {
                instance = new SingletonLanHan03();
            }
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程安全,同步代码块):Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 5. 懒汉式(线程安全,同步代码块)
        SingletonLanHan03 singletonLanHan03 = SingletonLanHan03.getInstance();
        singletonLanHan03.hello();
    }
}

revérifier (recommandé)

Avantages et inconvénients

  1. Le concept Double-Check est souvent utilisé dans le développement multi-thread.Comme indiqué dans le code, nous avons effectué deux if (singleton == null)vérifications, afin que la sécurité des threads puisse être garantie.

  2. De cette façon, le code d'instanciation n'a besoin d'être exécuté qu'une seule fois, et lorsqu'on y accède à nouveau plus tard, il est jugé if (singleton == null)et l'objet d'instanciation est renvoyé directement, ce qui évite également la synchronisation répétée des méthodes.

  3. Sécurité des threads, chargement paresseux, haute efficacité

en conclusion:

Dans le développement réel, il est recommandé d'utiliser ce modèle de conception singleton à double vérification !

exemple de code

Mode singleton : SingletonDoubleCheck.java

public class SingletonDoubleCheck {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonDoubleCheck() {}

    /** 2. 本类内部使用volatile关键字定义静态的实例变量,volatile 保证可见性和禁止指令重排序 */
    private static volatile SingletonDoubleCheck instance;

    /** 3. 提供公有的静态方法 */
    public static synchronized SingletonDoubleCheck getInstance() {
        // 加入双重检查代码,解决线程不安全的问题,解决懒加载问题
        if (instance == null) {
            synchronized (SingletonDoubleCheck.class) {
                if (instance == null) {
                    instance = new SingletonDoubleCheck();
                }
            }
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("双重检查:Hello world!");
    }
}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 6. 双重检查
        SingletonDoubleCheck singletonDoubleCheck = SingletonDoubleCheck.getInstance();
        singletonDoubleCheck.hello();
    }
}

Classe interne statique (recommandé)

Lorsque la classe externe est chargée, la classe interne statique ne sera pas chargée, ce qui assure le problème de chargement paresseux.

Lorsque la méthode est appelée getInstance(), la classe interne statique sera instanciée et les variables statiques de la classe interne statique seront utilisées. Lorsque la JVM charge la classe, elle est thread-safe.

Avantages et inconvénients

  1. Cette méthode utilise le mécanisme de chargement de classe pour s'assurer qu'il n'y a qu'un seul thread lors de l'initialisation de l'instance.

  2. Dans la méthode de classe interne statique, lorsque la classe externe est chargée, elle ne sera pas instanciée immédiatement, mais lorsqu'elle doit être instanciée, la méthode sera appelée pour charger getInstance()la classe interne, complétant ainsi l'instanciation de la classe externe.

  3. Les propriétés statiques de la classe ne seront initialisées que lorsque la classe est chargée pour la première fois, donc ici, la JVM nous aide à assurer la sécurité du thread. Lorsque la classe est initialisée, les autres threads ne peuvent pas entrer.

  4. Avantages : éviter l'insécurité des threads, utiliser des caractéristiques de classe interne statiques pour obtenir un chargement paresseux, un rendement élevé

en conclusion:

Utilisation recommandée!

exemple de code

Modèle de singleton : SingletonInnerClass.java

public class SingletonInnerClass {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonInnerClass() {}

    /** 2. 本类内部使用volatile关键字定义静态的实例变量 */
    private static volatile SingletonInnerClass instance;

    /** 3. 提供公有的静态方法 */
    public static synchronized SingletonInnerClass getInstance() {
        // 直接返回静态内部类的静态变量
        return SingletonInstance.INSTANCE;
    }

    /** 4. 提供一个静态内部类 */
    private static class SingletonInstance {
        private static final  SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }

    /** 5. 代码实现 */
    public void hello() {
        System.out.println("静态内部类:Hello world!");
    }
}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 7. 静态内部类
        SingletonInnerClass singletonInnerClass = SingletonInnerClass.getInstance();
        singletonInnerClass.hello();
    }
}

énumération (recommandé)

L'utilisation de l'énumération pour implémenter le mode singleton peut non seulement éviter les problèmes de synchronisation multi-thread, mais également empêcher la désérialisation de recréer de nouveaux objets.

en conclusion:

Utilisation recommandée!

exemple de code

Modèle de singleton : SingletonEnum.java

public enum SingletonEnum {

    /** 1. 实例化对象 */
    INSTANCE;

    /** 2. 代码实现 */
    public void hello() {
        System.out.println("枚举:Hello world!");
    }

}

Appelant : SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 8. 枚举
        SingletonEnum.INSTANCE.hello();
    }
}

Modèle singleton en JAVA

java.lang.Runtime

conclusion

1. Pour plus de modèles de conception, veuillez consulter la colonne [Modèles de conception]

2. Des exemples de codes pertinents peuvent être téléchargés :  Exemples de modèles de conception courants en Java

PS : [  Exemple de modèles de conception courants  en Java] a inclus  le code impliqué dans la colonne [Design Pattern]  . Si vous l'avez déjà téléchargé, vous n'avez pas besoin de le télécharger à nouveau~

Si le contenu ci-dessus est incorrect ou doit être complété, veuillez demander plus de conseils, et il sera mis à jour et corrigé à temps ~

Les commentaires sont les bienvenus ~ Merci pour vos éloges ~

おすすめ

転載: blog.csdn.net/pjymyself/article/details/121929248